app嵌html屡见不鲜, 本文描述加载简单的html网页。
首先说明需求: 有网的状态直接从获取html网页并且缓存, 无网状态先从缓存读取html, 若不成功则加载本地html文件, 并且将本地html文件写入缓存, 以便下次读取.
1.加载html网页, viewWillAppear或者viewDidLoad.
以下QAUrl均为html完整的url
2.若成功, 就在成功的代理方法里, 将网页端html写入缓存
3.不成功,在失败的代理方法里, 加载磁盘缓存或者本地html,其中isNetConnected是指是否连接到互联网, 默认是true,加载失败后置为false.
fileprivate var isNetConnected: Bool = true // 是否连接到互联网
4.同样,此次成功后,在代理方法里,将本地html文件写入缓存
5.代理方法的里很简洁
6.需要注意的是
(1)拼接缓存地址时, 如果html的URL类似于" http://10.0.4.2:82/app/qa.html ",不能作为地址拼接,否则无法缓存.
(2)笔者将拼接地址统一写成"/Caches/feedback.html",若有新的缓存,则地址被覆盖,不会导致缓存多个相同文件,一般无需清理或者导致内存警告
(3)本文不涉及缓存图片, js交互等问题
7.补充:
开发过程中,笔者又遇到了一个问题,有网的情况下,网页也可能出现加载不成功.这个时候如果只是加载网页就会什么都没有.所以在viewWillAppear或者viewDidLoad里应该有个判断
如果请求request返回的finish是true即成功,则加载html网页,不成功则加载缓存.
当我们使用webview加载html资源时,本质上就是向服务器索取资源的http请求过程,如果我们不注意资源的缓存策略的话,就可能会造成这样那样的问题,比如:实时性要求较高的功能却老是走缓存不更新,有些基本不会变动的页面却又每次都重新去服务器拉请求。
iOS自带的缓存策略,提供了一个内存和磁盘混合的缓存,一共有7种缓存策略,使用较多的是其中的四种( 下方编号1,2,5,6 )
上面介绍了iOS自带的缓存控制 NSURLRequestCachePolicy ,也说到当 NSURLRequestCachePolicy 设为默认的 NSURLRequestUseProtocolCachePolicy 时,主要是根据http的缓存策略来决定是否使用缓存。
那么就简单的介绍一下,http的缓存控制和缓存校验。
在http中,控制缓存开关的字段有两个,Pragma和Cache-Control
Pragma有两个字段no-cache和expires,当pragma为no-cache时表示禁用缓存,expires的值是一个GMT时间,表示该缓存的有效时间。但是已经被逐步抛弃了,有些网站为了向下兼容还保留了这两个字段。
Cache-Control除了在响应中使用,在请求中也可以使用。
在请求中使用,Cache-Control可选的值有:
在响应中使用,Cache-Control可选的值有:
在缓存中,我们需要一个机制来验证缓存是否有效。比如服务器的资源更新了,客户端需要及时刷新缓存;又或者客户端的资源过了有效期,但服务器上的资源还是旧的,此时不需要重新发送。缓存校验就是用来解决这些问题的,在http1.1中,主要关注下 Last-Modified 和 etag 这两个字段。
服务端在返回资源时,会将该资源的最后更改时间通过 Last-Modified 字段返回给客户端。客户端下次请求时通过 If-Modified-Since 或者 If-UnModified-Since 带上 Last-Modified ,服务端检查该时间是否与服务器的最后修改时间一致:如果一致,则返回304状态码,不反悔资源;如果不一致,则返回200和修改后的资源,并带上新的时间。
单纯的以修改时间来判断还是有缺陷,比如文件的最后修改时间变了,但内容没变。对于这样的情况,我们可以使用etag来处理。
etag的方式是这样:服务器通过某个算法对资源进行计算,取得一串值(类似于文件的md5值),之后将该值通过etag返回给客户端,客户端下次请求时通过If-None-Match或If-Match带上该值,服务器对该值进行对比校验:如果一致则不要返回资源。
当我们的webview缓存到一定的峰值的时候,需要手动的清除一下wenview的缓存,方法如下:
找出web缓存的路径,清空该路径
webKit除了清除缓存的API
觉得有用,请帮忙点亮红心
Better Late Than Never!
努力是为了当机会来临时不会错失机会。
共勉!
最近关于web界面偶有反馈拉到旧的界面,导致出现一些异常情况;
因此,对web资源的加载、缓存进行一些梳理。
以某个web界面加载为例,当我们不使用浏览器缓存时,返回的response是完整的html文本,同时还附带着ETag;
如果打开缓存策略,则请求头带了If-None-Match(对应直接的ETag: "5e58f3dd-b0b"),此时回包体积明显变小,同时返回码是304;
当请求或者response带有no-cache、max-age=0时,缓存的资源仍可使用,但是会通过请求进行验证,类似上面的ETag,返回 304表示Not Modified ,可以继续使用;( no-cache,并非放弃缓存 )
而当max-age=3600时,表示资源有效时间是1个小时,在有效时间内不需要通过后端验证,此时不需要发起网络请求,会直接由cache返回数据。(前提是客户端的request的header,没有设置no-cache和max-age=0)
一个资源的请求流程:
关于request和response的总结:
在前面的client->cache->server基础上,web缓存SDK所在的层级是在cache和server之间;
cache属于浏览器自身的缓存,web缓存SDK相当于代理,阻断了浏览器发起的网络请求,如果本地有匹配的数据,则使用本地数据返回,如果没有使用网络请求,最终所有的数据都会加载到cache;
web缓存SDK和上面的缓存策略并没有关系,上面的缓存策略决定是否要发起网络请求去验证资源、加载资源,而web缓存SDK则是在请求发起之后直接返回,类似charles的map local;
线上的web界面出现一个bug,web的同学修复完之后,手动刷新了cdn的资源和业务缓存SDK的资源。
但是部分html配置的no-cache失效(设置了max-age=xxx),导致如果之前进入过在拉到之前,会使用浏览器缓存;导致本次启动会一直使用旧的的界面。
解决方案:
1、更换该界面的url,使得cache失效;
2、清除webKit的缓存;
HTTP协议的学问博大精深,这次借此对缓存相关知识进行一次梳理。
参考链接
https://stackoverflow.com/questions/27105094/how-to-remove-cache-in-wkwebview