最近在写一个web容器,容器有一一个小功能是要对web做缓存,所以最近一直研究ios的web缓存,在研究过程中遇到不少问题也收货颇多,现总结如下:
web缓存的目的:节省服务器资源;使页面加载更流畅,减少等待时间增加用户体验;节省用户流量等。。。
web缓存有很多种方法NSURLCache、App Cache(Manifest文件)、NSURLProtocol:
1、NSURLCache(ios系统自带的,并不知是web缓存才会有):
(1)NSURLCache-http响应:
在我们发request请求时,ios系统会默认参与缓存,使用的是默认的NSURLCache类,可以通过NSURLCache的sharedURLCache方法获取。request在初始化的时候可以选择cachePolicy值(缓存策略)
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
NSURLRequestUseProtocolCachePolicy = 0,
NSURLRequestReloadIgnoringLocalCacheData = 1,// 从不读取缓存,但请求后将response缓存起来
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
NSURLRequestReturnCacheDataElseLoad = 2,// (可能读取的是过期数据)缓存中没有才去发起请求加载,有就不进行网络请求了
NSURLRequestReturnCacheDataDontLoad = 3,// (可能读取的是过期数据)缓存中没有不加载,绝不发起网络请求,缓存中没有则返回错误
NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
};
request默认使用NSURLRequestUseProtocolCachePolicy=0;即根据http响应数据进行缓存,这就需要研究下response的几个字段了:
在根据响应返回的字段又分为强制缓存和对比缓存:https://blog.csdn.net/sinat_20894673/article/details/89061172
1.1.强制缓存:对于第一次请求资源,在没有资源缓存的情况下,会发送资源请求请求服务器获取对应的资源。在http响应头会有强制缓存的标志(Expires/Cache-Control)。分别对应http1.0和http1.1的缓存规则。当下次请求对应资源的时候,根据强制缓存的标志,如果还在缓存期内,那么直接使用本地缓存,不在发送网络请求。
1.1.1》Expires:在http1.0中,代表资源过期时间。使用绝对时间来标记资源的过期时间,但是由于服务器与客户端之间可能存在差异,会导致缓存的不准确。eg:Expires:Sat,06 Apr 2019 14:11:37 GMT
1.1.2》Cache-Control:http1.1,一般取值private、public、no-cahe(使用对比缓存来验证缓存数据)、max-age=300s(300s有效期)、no-store(不使用缓存,一般来说都会设置缓存);默认private
1.2.对比缓存:在没有设置强制缓存的情况下,就会比较对比缓存。在使用对比缓存的时候,会将之前在客户端的对比缓存的标志发送到服务器,与服务器上的版本进行比较,如果资源没有被修改过,那么直接返回304,此时使用本地缓存的资源,若资源已过期,则返回新的资源,此时的状态码是200。
1.2.1》Last-Modified:在响应请求时,告诉浏览器的最后修改时间,http1.0。但是由于该标志是根据文件的修改时间决定的,而且是基于秒级,如果在一秒内对文件修改两次的话,此时last-modified的值是一致的。
1.2.1》Etag:是资源的唯一标志,在资源没有发生变化的时候,Etag值不变,这个标记同样会通过响应头返回给客户端。该标志就是为了弥补last-modified的不足。http1.1
Etag 主要为了解决 Last-Modified 无法解决的一些问题:
1、一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
2、某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
3、某些服务器不能精确的得到文件的最后修改时间。
总结
对于静态资源的缓存一般都会设置强制缓存和对比缓存,当强制缓存与对比缓存同时存在的时候,优先使用强制缓存,在强制缓存中,cache-control的优先级大于expires。当强制缓存存在的时候,浏览器直接使用本地缓存,并且请求返回200,此时的请求是不会请求服务器的。而当强制缓存过期的时候,则会使用对比缓存,此时会发送一个请求到服务器,如果此时文件还未被更新,则请求返回304,并且会使用本地的缓存文件。否则服务器返回200,并且返回对应的新的资源。
(2)NSURLCache-存储位置:
1》UIWebView(用UIWebView加载百度首页为例)https://blog.csdn.net/fishmai/article/details/60127023
用一段示例代码说明:/Users/yangyangzi/Desktop/testUiweb/uiweb/dd.TestUIWeb\ 2019-09-07\ 19\:58.49.523.xcappdata/AppData/Library/Caches/dd.TestUIWeb (注:dd.TestUIWeb为bundleid)
在沙盒的caches目录下:
NSURLCache-内容详解:
主要内容都在Cache.db数据库中,下面来看下此数据库中三个关键的表:
cfurl_cache_response 中根据request_key查到entry_ID
cfurl_cache_blob_data中根据entry_ID找到response_object
cfurl_cache_receiver_data中根据entry_ID找到receiver_data
根据receiver_data又能找到与Cache.db同级的文件夹fsCachedData中的对应文件,例如上边(四张图中选中的行的entry_ID=5的图片即为plus_log_web.png 百度logo)
2》WKWebView(用WKWebView加载百度首页为例)https://www.cnblogs.com/lolDragon/p/6861370.html
解开wk的包查看沙盒目录如下:
查看cache.db详情如下:
的确你没看错,wk的cache.db库里的三个关键表格是空的,而且不像UIweb,wk的沙盒目录里没有fsCachedData文件夹,但是wk的沙盒中多了两个Webkit文件夹,其中一个在Caches文件夹下,另一个与Caches文件夹同层。先来看下这个Caches文件夹下的Webkit文件夹:
WebKit文件夹里面存储的就是WKWebVieW下面的缓存文件了(包含了JS/CSS/图片等);
分析:wkweb的Cache.db文件是空的,说明在推出wkwebview后,ios系统将web的缓存和NSURLCahe分开了,(用AFN发请求发现,Cache.db中有url存储,说明Cache.db只存储除wkweb发送的请求,而wkweb的网络缓存都放在了webkit文件夹下)
与Caches文件夹同层的webkit文件夹,应该是wkwebview的磁盘存储了。
2、App Cache(Manifest文件):这里就需要web端的同学去操作了:Manifest文件是web端同学在html中的一个manifest
创建 .manifest的文件:https://www.cnblogs.com/lolDragon/p/6861370.html
manifest文件首先必须已 CACHE MANIFEST开头, 然后包含了三个部分CACHE: NETWORK: FALLBACK:三个部分,其中CACHE下边写的是要缓存的文件。
application cache缓存的位置:
不推荐
3、使用NSURLProtocol缓存web文件:
这种方法也是我最近在扣的,很多坑里边,考虑到篇幅问题,再新写一篇
NSURLCache缓存的位置:https://www.jianshu.com/p/e84f2e897e18;
ios html5使用缓存并及时更新方案总结:https://www.cnblogs.com/lolDragon/p/6861370.html
清除缓存:https://www.cnblogs.com/lolDragon/p/6774509.html
https://www.itcodemonkey.com/article/14997.html
webkit的缓存机制:https://blog.csdn.net/yl02520/article/details/22300467
你可能并不需要拦截webview的静态资源:https://www.jianshu.com/p/40d9f599f869
http请求中静态资源的缓存:https://blog.csdn.net/sinat_20894673/article/details/89061172
NSURLCache:https://nshipster.cn/nsurlcache/
ios wkwebview(NSURLProtol)拦截js、css、图片资源:https://www.jianshu.com/p/4fc13d4d5607
NSURLCache使用UIWebViewURL拦截:https://www.jianshu.com/p/3fdfef453513