OkHttp3源码详解(四)缓存策略,万分膜拜

//如果当前缓存不符合要求,将其close

if (cacheCandidate != null && cacheResponse == null) {

  closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.

}



// 如果不能使用网络,同时又没有符合条件的缓存,直接抛504错误

if (networkRequest == null && cacheResponse == null) {

  return new Response.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 (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());

  }

}



// 如果既有缓存,同时又发起了请求,说明此时是一个Conditional Get请求

if (cacheResponse != null) {

  // 如果服务端返回的是NOT_MODIFIED,缓存有效,将本地缓存和网络响应做合并

  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)) {

    // 将网络响应写入cache中

    CacheRequest cacheRequest = cache.put(response);

    return cacheWritingResponse(cacheRequest, response);

  }



  if (HttpMethod.invalidatesCache(networkRequest.method())) {

    try {

      cache.remove(networkRequest);

    } catch (IOException ignored) {

      // The cache cannot be written.

    }

  }

}



return response; 

```



}  

核心逻辑都以中文注释的形式在代码中标注出来了,大家看代码即可。通过上面的代码可以看出,几乎所有的动作都是以CacheStrategy缓存策略为依据做出的,那么接下来看下缓存策略是如何生成的,相关代码实现在CacheStrategy$Factory.get()方法中:



\[CacheStrategy$Factory\]



```

/**

 * Returns a strategy to satisfy {@code request} using the a cached response {@code response}.

 */

public CacheStrategy get() {

  CacheStrategy candidate = getCandidate();



  if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {

    // We're forbidden from using the network and the cache is insufficient.

    return new CacheStrategy(null, null);

  }



  return candidate;

}



/** Returns a strategy to use assuming the request can use the network. */

private CacheStrategy getCandidate() {

  // 若本地没有缓存,发起网络请求

  if (cacheResponse == null) {

    return new CacheStrategy(request, null);

  }



  // 如果当前请求是HTTPS,而缓存没有TLS握手,重新发起网络请求

  if (request.isHttps() && cacheResponse.handshake() == null) {

    return new CacheStrategy(request, null);

  }



  // If this response shouldn't have been stored, it should never be used

  // as a response source. This c
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值