overridefunintercept(chain: Interceptor.Chain): Response { val call = chain.call() //1、如果HttpClient设置cache,则会通过此cache的get方法:传入当前request,获取一个候选缓存——>response val cacheCandidate = cache?.get(chain.request()) //2、获取当前系统时间 val now = System.currentTimeMillis() //3、根据CacheStrategy的工厂Factory,构造一个一个CacheStrategy对象,可以看出是通过传入时间、request、cacheCandidate计算一个缓存策略工厂. val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute() //4、取出networkRequest(当前的网络请求)、cacheResponse(缓存) val networkRequest = strategy.networkRequest val cacheResponse = strategy.cacheResponse //5、对相应进行跟踪计数 cache?.trackResponse(strategy) val listener = (call as? RealCall)?.eventListener ?: EventListener.NONE //6、如果之前还候选缓存不为空,但通过计算处理后cacheResponse为空,那么就关闭候选缓存的资源 if (cacheCandidate != null && cacheResponse == null) { // The cache candidate wasn't applicable. Close it. cacheCandidate.body?.closeQuietly() } //7、如果要发送的请求为空&也没有缓存,那么直接返回504给客户端,并且body为空 // If we're forbidden from using the network and the cache is insufficient, fail. if (networkRequest == null && cacheResponse == null) { return Response.Builder() .request(chain.request()) .protocol(Protocol.HTTP_1_1) .code(HTTP_GATEWAY_TIMEOUT) .message("Unsatisfiable Request (only-if-cached)") .body(EMPTY_RESPONSE) .sentRequestAtMillis(-1L) .receivedResponseAtMillis(System.currentTimeMillis()) .build().also { listener.satisfactionFailure(call, it) } } //8、如果不需要发送网络请求,那么直接缓存返回给客户端 // If we don't need the network, we're done. if (networkRequest == null) { return cacheResponse!!.newBuilder() .cacheResponse(stripBody(cacheResponse)) .build().also { listener.cacheHit(call, it) } } //7、缓存命中的监听 if (cacheResponse != null) { listener.cacheConditionalHit(call, cacheResponse) } elseif (cache != null) { listener.cacheMiss(call) } //8、此时没有可用缓存,继续调用链的下一步,在这里就是发起真正的网络请求 var networkResponse: Response? = null try { networkResponse = chain.proceed(networkRequest) } finally { // If we're crashing on I/O or otherwise, don't leak the cache body. if (networkResponse == null && cacheCandidate != null) { cacheCandidate.body?.closeQuietly() } } //10、在网络请求完成后,如果已经有了一个缓存,需要做一些其他条件的判断 // If we have a cache response too, then we're doing a conditional get. if (cacheResponse != null) { //11、如果响应码是304,表面未改变,说明无需再次传输请求的内容,那就把缓存返回给客户端 if (networkResponse?.code == HTTP_NOT_MODIFIED) { val response = cacheResponse.newBuilder() .headers(combine(cacheResponse.headers, networkResponse.headers)) .sentRequestAtMillis(networkResponse.sentRequestAtMillis) .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis) .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build()
networkResponse.body!!.close()
// Update the cache after combining headers but before stripping the // Content-Encoding header (as performed by initContentStream()). cache!!.trackConditionalCacheHit() cache.update(cacheResponse, response) return response.also { listener.cacheHit(call, it) } } else { cacheResponse.body?.closeQuietly() } } //12、如果以上的条件都不成立,生成最终的response val response = networkResponse!!.newBuilder() .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build() //13、如果cache没有设置,response合法并且判断是可缓存,则调用cache的put方法存储响应 if (cache != null) { if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) { // Offer this request to the cache. val cacheRequest = cache.put(response) return cacheWritingResponse(cacheRequest, response).also { if (cacheResponse != null) { // This will log a conditional cache miss only. listener.cacheMiss(call) } } } //14、对于一些的请求方法:POST、PATCH、PUT、DELETE、MOVE不支持,把缓存移除 if (HttpMethod.invalidatesCache(networkRequest.method)) { try { cache.remove(networkRequest) } catch (_: IOException) { // The cache cannot be written. } } }
internalfunget(request: Request): Response? { val key = key(request.url) val snapshot: DiskLruCache.Snapshot = try { cache[key] ?: returnnull } catch (_: IOException) { returnnull// Give up because the cache cannot be read. }
fun compute(): CacheStrategy { val candidate = computeCandidate()
// We're forbidden from using the network and the cache is insufficient. if (candidate.networkRequest != null && request.cacheControl.onlyIfCached) { return CacheStrategy(null, null) }
// 2、如果是https请求,并且没有TSL握手,那自然没有缓存 if (request.isHttps && cacheResponse.handshake == null) { return CacheStrategy(request, null) } //3、判断cacheResponse是否是可缓存,如果cacheResponse是不符合规则的,自然也不需要。 if (!isCacheable(cacheResponse, request)) { return CacheStrategy(request, null) //4、如果配置了不缓存或者request headers中包含If-Modified-Since或者If-None-Match val requestCaching = request.cacheControl if (requestCaching.noCache || hasConditions(request)) { return CacheStrategy(request, null) }
val responseCaching = cacheResponse.cacheControl //5、获取缓存的age val ageMillis = cacheResponseAge() //6、从服务日期开始,返回响应最新事件 var freshMillis = computeFreshnessLifetime() //7、和缓存最大age比较 if (requestCaching.maxAgeSeconds != -1) { freshMillis = minOf(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds.toLong())) } //8、表示客户端希望获取一个能在指定的秒数内保持其最新状态的响应。 var minFreshMillis: Long = 0 if (requestCaching.minFreshSeconds != -1) { minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds.toLong()) } //9、表示响应不能已经过时超过该给定的时间。 var maxStaleMillis: Long = 0 if (!responseCaching.mustRevalidate && requestCaching.maxStaleSeconds != -1) { maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds.toLong()) }
if (!responseCaching.noCache && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) { val builder = cacheResponse.newBuilder() //提示服务器提供的响应已过期 if (ageMillis + minFreshMillis >= freshMillis) { builder.addHeader("Warning", "110 HttpURLConnection \"Response is stale\"") } //如果缓存服务器采用启发式方法,将缓存的有效期设置为24小时,而该响应时间超过24小时则触发该提示 val oneDayMillis = 24 * 60 * 60 * 1000L if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) { builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\"") } //10、返回一个不需要请求带缓存的CacheStrategy return CacheStrategy(null, builder.build()) } //注释11 构造一个需要请求和缓存的CacheStrategy // Find a condition to add to the request. If the condition is satisfied, the response body // will not be transmitted. val conditionName: String val conditionValue: String? when { etag != null -> { conditionName = "If-None-Match" conditionValue = etag }
If this response shouldn’t have been stored, it should never be used as a response source. This check should be redundant as long as the persistence store is well-behaved and the rules are constant.