浏览器缓存,相信前端同学对这几个字眼非常熟悉,那么今天重新来解读一下这个概念,并根据其原理扩展到native中如何使用。
第一部分,先来谈谈浏览器缓存原理,这样的文章网上都已经很了,但为了第二部分叙述,此处还是啰嗦一下。可参考浏览器缓存机制。
这里主要介绍跟HTTP相关的缓存,主要依赖Expires/Cache-Control和304返回码实现的缓存逻辑。
HTTP1.0中请求头中存在Expires字段,顾名思义,用来设置网络资源的过期时间;
HTTP1.1对缓存头信息进行了丰富,包括Cache-Control,以及跟Cache-Control相关的Last-Modified/If-Modified-Since和Etag/If-None-Match,
其中Cache-Control中的max-age可以设置资源的缓存时间,而Last-Modified是服务器告诉浏览器资源的最后修改时间,Etag是服务器告诉浏览器资源的Hash值,
用来代表资源的 唯一值(比如百度云盘秒传机制,即检测文件Hash值后在网络库中进行匹配,省去无效的上传时间)。
当浏览器第一次访问服务器资源后,会对服务器返回的头信息进行存储,方便以后请求时判断缓存是否有效。
配合这些字段浏览器即可实现对资源的缓存控制,主要流程如下:
1.如果请求不支持Cache-Control,则使用Expires来判断资源是否过期;
2.如果请求支持Cache-Control,则先判断(第一次请求时间)+max-age>(当先请求时间),如果成立则直接读取本地缓存(也就是Chrome DevTool中看到的from cache);
3.如果不成立,则判断资源是否存在Etag,如果存在该字段,则在请求中加上If-None-Match头并带入Etag值,等待服务器判断该Etag是否无效,如果有效则返回304,直接读取本地缓存,如果Etag无效则返回200并返回新的资源;
4.如果不存在Etag资源,则判断是否存在Last-Modified,如果存在则在请求中加上If-Modified-Since头并带入Last-Modified值,等待服务器判断资源是否过期,如果未过期则返回304,直接读取本地缓存,如果过期则返回200并返回新的资源;
5.如果这Etag和Last-Modified两个信息都不存在,则直接向服务器发起新的请求,服务器返回200并返回新的资源,并将其缓存到浏览器本地。
至此,浏览器请求时缓存机制已全部完成,其流程如下图描述。
第二部分,聊完了浏览器的缓存机制,那么在其他客户端场景是否能运用该机制,起到缓存网络资源作用。这里主要介绍Android客户端模拟浏览器缓存请求网络图片。
在移动客户端Android中请求网络资源时,我们可以利用HTTP自带缓存头特性来缓存图片。那么如何来获取及保存Cache-Control/Last-Modified/Etag等缓存相关参数,
则需要在本地文件系统中建立相应数据库及表用来存储这些信息。大致如下表。
ID | PROTO | HOST | PORT | PATH | PARAMS | First-Request-Time | CACHE-CONTROL | LAST-MODIFIED | ETAG |
1 | http | secure.*.com | 80 | /webapp/index | token=xxx | 2015-09-10 11:16:43 | max-age:30000 | Thu, 17 Sep 2015 11:16:43 GMT | 8dYKoCv***Rn6XX0= |
前面的PROTO/HOST/PORT/PATH/PARAMS主要用来构建HTTP URL,后4个则用来资源缓存相关的信息,主要流程与浏览器请求网络资源基本一致。
先判断Cache-Control是否过期,如果过期则检查ETAG,如果ETAG没有则检查LAST-MODIFIED,如果LAST-MODIFIED也没有则直接请求,将请求对应的返回头信息写入数据库即可。
上面基本描述了模拟浏览器缓存构造Android客户端缓存的原理,其细节则不再描述,可参考开源库GALHTTPREQUEST。