从网络请求过程看OkHttp拦截器( 三 )


简单的说, gzip 就是一种压缩方式,可以将数据进行压缩,在添加头部信息的时候就添加了这样一个头部:
requestBuilder.header("Accept-Encoding", "gzip")这一句其实就是在告诉服务器,客户端所能接受的文件的压缩格式,这里设置了 gzip 之后,服务器看到了就能把响应报文数据进行 gzip 压缩再传输,提高传输效率,节省流量 。
所以请求之后的这段关于 gzip 的处理其实就是客户端对压缩数据进行解压缩,而 GzipSource 是okio库里面一个进行解压缩读取数据的类 。
缓存拦截器(CacheInterceptor)继续看缓存拦截器— CacheInterceptor  。
class CacheInterceptor(internal val cache: Cache?) : Interceptor {@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {//取缓存val cacheCandidate = cache?.get(chain.request())//缓存策略类val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()val networkRequest = strategy.networkRequestval cacheResponse = strategy.cacheResponse// 如果不允许使用网络,并且缓存数据为空if (networkRequest == null && cacheResponse == null) {return Response.Builder().request(chain.request()).protocol(Protocol.HTTP_1_1).code(HTTP_GATEWAY_TIMEOUT)//504.message("Unsatisfiable Request (only-if-cached)").body(EMPTY_RESPONSE).sentRequestAtMillis(-1L).receivedResponseAtMillis(System.currentTimeMillis()).build().also {listener.satisfactionFailure(call, it)}}// 如果不允许使用网络,但是有缓存if (networkRequest == null) {return cacheResponse!!.newBuilder().cacheResponse(stripBody(cacheResponse)).build().also {listener.cacheHit(call, it)}}networkResponse = chain.proceed(networkRequest)// 如果缓存不为空if (cacheResponse != null) {//304,表示数据未修改if (networkResponse?.code == HTTP_NOT_MODIFIED) {cache.update(cacheResponse, response)return response}}//如果开发者设置了缓存,则将响应数据缓存if (cache != null) {if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {//缓存headerval cacheRequest = cache.put(response)//缓存bodyreturn cacheWritingResponse(cacheRequest, response)}}return response}}还是分两部分看:

  • 请求之前 ,通过request获取了缓存,然后判断缓存为空,就直接返回code为504的结果 。如果有缓存并且缓存可用,则直接返回缓存 。
  • 请求之后 ,如果返回 304 代表服务器数据没修改,则直接返回缓存 。如果 cache 不为空,那么就把 response 缓存下来 。
这样看是不是和上面我们说过的缓存机制对应上了?请求之前就是处理 强制缓存 的情况,请求之后就会处理 协商缓存 的情况 。
但是还是有几个问题需要弄懂:
1、缓存是怎么存储和获取的?
2、每次请求都会去存储和获取缓存吗?
3、缓存策略(CacheStrategy)到底是怎么处理网络和缓存的?networkRequest什么时候为空?
首先,看看缓存哪里取的:
val cacheCandidate = cache?.get(chain.request())internal fun get(request: Request): Response? {val key = key(request.url)val snapshot: DiskLruCache.Snapshot = try {cache[key] ?: return null}val entry: Entry = try {Entry(snapshot.getSource(ENTRY_METADATA))}val response = entry.response(snapshot)if (!entry.matches(request, response)) {response.body?.closeQuietly()return null}return response}通过 cache.get 方法获取了response缓存,get方法中主要是用到了请求 Request的url 来作为获取缓存的标志 。
所以我们可以推断,缓存的获取是通过请求的url作为key来获取的 。
那么 cache 又是哪里来的呢?
val cache: Cache? = builder.cacheinterceptors += CacheInterceptor(client.cache)class CacheInterceptor(internal val cache: Cache?) : Interceptor没错,就是实例化 CacheInterceptor 的时候传进去的,所以这个cache是需要我们创建 OkHttpClient 的时候设置的,比如这样:
val okHttpClient =OkHttpClient().newBuilder().cache(Cache(cacheDir, 10 * 1024 * 1024)).build()这样设置之后, okhttp 就知道 cache 存在哪里,大小为多少,然后就可以进行服务器响应的缓存处理了 。
所以第二个问题也解决了,并不是每次请求都会去处理缓存,而是开发者需要去设置缓存的存储目录和大小,才会针对缓存进行这一系列的处理操作 。
最后再看看缓存策略方法 CacheStrategy.Factory().compute()
class CacheStrategy internal constructor(val networkRequest: Request?,val cacheResponse: Response?)fun compute(): CacheStrategy {val candidate = computeCandidate()return candidate}private fun computeCandidate(): CacheStrategy {//没有缓存情况下,返回空缓存if (cacheResponse == null) {return CacheStrategy(request, null)}//...//缓存控制不是 no-cache,且未过期if (!responseCaching.noCache && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) {val builder = cacheResponse.newBuilder()return CacheStrategy(null, builder.build())}return CacheStrategy(conditionalRequest, cacheResponse)}


推荐阅读