OkHttp - CacheInterceptor源码简析
2019年7月10日
Serves requests from the cache and writes responses to the cache
HTTP 缓存
Expires (强制缓存)
Expires 的值为服务端返回的到期时间,即下一次请求时请求时间小于服务端返回的到期时间则直接使用缓存数据
Expires 是 HTTP 1.0 的产物,在 HTTP 1.1 中用 Cache-Control 替代
Cache-Control (强制缓存)
Cache-Control 的取值有 private、public、no-cache、max-age,no-store 等,默认为private
指令 | 意义 |
---|---|
private | 表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它) |
public | 表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存 |
no-cache | 在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证 |
no-store | 缓存不应存储有关客户端请求或服务器响应的任何内容 |
max-age= |
设置缓存存储的最大周期,超过这个时间缓存被认为过期 |
s-maxage= |
覆盖max-age 或者Expires 头,但是仅适用于共享缓存 |
max-stale[= |
表明客户端愿意接收一个已经过期的资源。可以设置一个可选的秒数,表示响应不能已经过时超过该给定的时间 |
min-fresh= |
表示客户端希望获取一个能在指定的秒数内保持其最新状态的响应 |
Last-Modified (对比缓存)
服务器在响应请求时,告诉浏览器资源的最后修改时间
If-Modified-Since (对比缓存)
再次请求服务器时,通过此字段通知服务器上次请求时间,服务器返回的资源最后修改时间,服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对
- 若资源的最后修改时间大于 If-Modified-Since ,说明资源又被改动过,则响应整片资源内容,返回状态码 200
- 若资源的最后修改时间小于或等于 If-Modified-Since ,说明资源无新修改,则响应 HTTP 304,告知浏览器继续使用所保存的 Cache
Etag (对比缓存)
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)
If-None-Match (对比缓存)
再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识,服务器收到请求后发现有头 If-None-Match 则与被请求资源的唯一标识进行比对
- 不同,说明资源又被改动过,则响应整片资源内容,返回状态码 200
- 相同,说明资源无新修改,则响应 HTTP 304,告知浏览器继续使用所保存的 Cache
源码解析
intercept(chain: Interceptor.Chain)
1 | class CacheInterceptor(internal val cache: InternalCache?) : Interceptor { |
- 通过 Request 尝试到 cache 中拿缓存
- 根据 response , time , request 创建一个缓存策略,用于判断怎样使用缓存
- 如果缓存策略中设置禁止使用网络,并且缓存又为空,则构建一个 504 的 Resposne 直接返回
- 缓存策略中设置不使用网络但有缓存,直接返回缓存
- 接着走后续拦截器的流程,chain.proceed(networkRequest)
- 当缓存存在的时候,如果网络返回的 304 Resposne,则使用缓存的 Resposne
- 构建网络请求的 Response
- 将 Response 缓存起来
- 返回 Response
这里的 cache 是 InternalCache
类型
InternalCache
1 | interface InternalCache { |
InternalCache
是一个接口,利用了面向接口编程的方式,接着查找哪个实现了或者说使用了这个接口,对应找到了Cache
这个类
Cache
1 | class Cache internal constructor( |
内部现实是 DiskLruCache
CacheStrategy
CacheStrategy 是一个策略器,负责判断是使用缓存还是请求网络获取新的数据,通过工厂创建
1 | class CacheStrategy internal constructor( |
在 CacheStrategy.Factory
的构造函数中
CacheStrategy.Factory#compute()
1 | class CacheStrategy internal constructor( |
- cacheResponse 为空,直接使用网络请求
isCacheable()
判断 cacheResponse 和 request 是否都支持缓存,只要一个不支持那么直接使用网络请求- requestCaching 判断 noCache 和 判断请求头是否有 If-Modified-Since 和 If-None-Match
- 判断 cacheResponse 的过期时间(包括 maxStaleMillis 的判断),如果没有过期,则使用 cacheResponse
- cacheResponse 过期了,那么如果 cacheResponse 有 eTag/If-None-Match 属性则将其添加到请求头中