publicCacheInterceptor(@NullableInternalCache cache){this.cache = cache;}@OverridepublicResponseintercept(Chain chain)throwsIOException{//这里的cache是在CacheInterceptor创建时候传入的,它的创建是在realCall中 interceptors.add(new CacheInterceptor(client.internalCache())); // client.internalCache()是创建OkHttpClient时候赋值的,但是需要通过OkHttpClient.Build去创建有个cache方法,传入Cache类//如果只是通过new OkHttpClient,则这个cache一定是nullResponse cacheCandidate = cache !=null? cache.get(chain.request()):null;long now =System.currentTimeMillis();CacheStrategy strategy =newCacheStrategy.Factory(now, chain.request(), cacheCandidate).get();Request networkRequest = strategy.networkRequest;Response cacheResponse = strategy.cacheResponse;if(cache !=null){
cache.trackResponse(strategy);}//如果缓存响应为空,则直接关闭缓存对象if(cacheCandidate !=null&& cacheResponse ==null){closeQuietly(cacheCandidate.body());// The cache candidate wasn't applicable. Close it.}// If we're forbidden from using the network and the cache is insufficient, fail.if(networkRequest ==null&& cacheResponse ==null){returnnewResponse.Builder().request(chain.request()).protocol(Protocol.HTTP_1_1).code(504).message("Unsatisfiable Request (only-if-cached)").body(Util.EMPTY_RESPONSE).sentRequestAtMillis(-1L).receivedResponseAtMillis(System.currentTimeMillis()).build();}// If we don't need the network, we're done.if(networkRequest ==null){return cacheResponse.newBuilder().cacheResponse(stripBody(cacheResponse)).build();}Response networkResponse =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){closeQuietly(cacheCandidate.body());}}// If we have a cache response too, then we're doing a conditional get.if(cacheResponse !=null){//状态未改变,使用缓存if(networkResponse.code()== HTTP_NOT_MODIFIED){Response 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;}else{closeQuietly(cacheResponse.body());}}Response response = networkResponse.newBuilder().cacheResponse(stripBody(cacheResponse)).networkResponse(stripBody(networkResponse)).build();if(cache !=null){//如果规则配置使用缓存,则更新最新的响应到缓存里if(HttpHeaders.hasBody(response)&&CacheStrategy.isCacheable(response, networkRequest)){// Offer this request to the cache.CacheRequest cacheRequest = cache.put(response);returncacheWritingResponse(cacheRequest, response);}//规则配置了不使用缓存,则删除缓存if(HttpMethod.invalidatesCache(networkRequest.method())){try{
cache.remove(networkRequest);}catch(IOException ignored){// The cache cannot be written.}}}return response;}
2 CacheStrategy.Factory
publicFactory(long nowMillis,Request request,Response cacheResponse){this.nowMillis = nowMillis;this.request = request;this.cacheResponse = cacheResponse;if(cacheResponse !=null){this.sentRequestMillis = cacheResponse.sentRequestAtMillis();this.receivedResponseMillis = cacheResponse.receivedResponseAtMillis();Headers headers = cacheResponse.headers();for(int i =0, size = headers.size(); i < size; i++){//遍历请求头,赋值String fieldName = headers.name(i);String value = headers.value(i);if("Date".equalsIgnoreCase(fieldName)){
servedDate =HttpDate.parse(value);
servedDateString = value;}elseif("Expires".equalsIgnoreCase(fieldName)){
expires =HttpDate.parse(value);}elseif("Last-Modified".equalsIgnoreCase(fieldName)){
lastModified =HttpDate.parse(value);
lastModifiedString = value;}elseif("ETag".equalsIgnoreCase(fieldName)){
etag = value;}elseif("Age".equalsIgnoreCase(fieldName)){
ageSeconds =HttpHeaders.parseSeconds(value,-1);}}}}/**
* Returns a strategy to satisfy {@code request} using the a cached response {@code response}.
*/publicCacheStrategyget(){CacheStrategy candidate =getCandidate();if(candidate.networkRequest !=null&& request.cacheControl().onlyIfCached()){// We're forbidden from using the network and the cache is insufficient.returnnewCacheStrategy(null,null);}return candidate;}
/** Returns a strategy to use assuming the request can use the network. */privateCacheStrategygetCandidate(){// No cached response.//没有缓存if(cacheResponse ==null){returnnewCacheStrategy(request,null);}// Drop the cached response if it's missing a required handshake.//https请求但是在ssl握手之前if(request.isHttps()&& cacheResponse.handshake()==null){returnnewCacheStrategy(request,null);}// 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.if(!isCacheable(cacheResponse, request)){returnnewCacheStrategy(request,null);}CacheControl requestCaching = request.cacheControl();//noCache:不能缓存,在hasConditions方法中判断当前的请求是否有包含If-None-Match或If-Modified-Since请求头,因为这两个请求头的作用是去询问服务器当前请求内容是否有发生改变,所以这个时候不能使用缓存if(requestCaching.noCache()||hasConditions(request)){returnnewCacheStrategy(request,null);}CacheControl responseCaching = cacheResponse.cacheControl();//已经存活的时长long ageMillis =cacheResponseAge();//允许存活的时长long freshMillis =computeFreshnessLifetime();//从request中更新时长if(requestCaching.maxAgeSeconds()!=-1){
freshMillis =Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds()));}long minFreshMillis =0;// 最小可存活时间if(requestCaching.minFreshSeconds()!=-1){
minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds());}long maxStaleMillis =0;// 最大可超过时间(比如,已经超出了可存活时间,但还可以延长点时间才算真正不可用)if(!responseCaching.mustRevalidate()&& requestCaching.maxStaleSeconds()!=-1){
maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds());}//有缓存且没有过期if(!responseCaching.noCache()&& ageMillis + minFreshMillis < freshMillis + maxStaleMillis){Response.Builder builder = cacheResponse.newBuilder();if(ageMillis + minFreshMillis >= freshMillis){
builder.addHeader("Warning","110 HttpURLConnection \"Response is stale\"");}long oneDayMillis =24*60*60*1000L;if(ageMillis > oneDayMillis &&isFreshnessLifetimeHeuristic()){
builder.addHeader("Warning","113 HttpURLConnection \"Heuristic expiration\"");}returnnewCacheStrategy(null, builder.build());}// Find a condition to add to the request. If the condition is satisfied, the response body// will not be transmitted.String conditionName;String conditionValue;//根据请求头,缓存不可用if(etag !=null){
conditionName ="If-None-Match";
conditionValue = etag;}elseif(lastModified !=null){
conditionName ="If-Modified-Since";
conditionValue = lastModifiedString;}elseif(servedDate !=null){
conditionName ="If-Modified-Since";
conditionValue = servedDateString;}else{returnnewCacheStrategy(request,null);// No condition! Make a regular request.}Headers.Builder conditionalRequestHeaders = request.headers().newBuilder();Internal.instance.addLenient(conditionalRequestHeaders, conditionName, conditionValue);Request conditionalRequest = request.newBuilder().headers(conditionalRequestHeaders.build()).build();//全新的请求和缓存returnnewCacheStrategy(conditionalRequest, cacheResponse);}