时间: 2020-08-31|tag: 58次围观|0 条评论

CacheInterceptor缓存拦截器分析

源码地址:https://github.com/square/okhttp

不知不觉来到了第三个拦截器,经过前面的两个拦截器:
RetryAndFollowUpInterceptor(初始化连接,重连);
BridgeInterceptor(头处理,Gzip, cookie处理)。

而这个 CacheInterceptor,是处理缓存相关的拦截器。

缓存知识

对于http 缓存的相关知识,可以参考:
http://www.cnblogs.com/chenqf/p/6386163.html
这文章中比较详细的讲解了,http中的缓存机制,以及一些基本的原理。如果你对缓存已经了解,可以忽略。

缓存拦截器基本流程

  1. 读取候选缓存;
  2. 创建缓存策略(根据头信息,判断强制缓存,对比缓存等策略);
  3. 根据策略,不使用网络,缓存又没有直接报错;
  4. 根据策略,不使用网络,有缓存就直接返回;
  5. 前面个都没有返回,读取网络结果(跑下一个拦截器);
  6. 接收到的网络结果,如果是code 304, 使用缓存,返回缓存结果(对比缓存)
  7. 读取网络结果;
  8. 对数据进行缓存;
  9. 返回网络读取的结果。

源码解读

  @Override public Response intercept(Chain chain) throws IOException {   //1. 读取候选缓存;    Response cacheCandidate = cache != null        ? cache.get(chain.request())        : null;    long now = System.currentTimeMillis();    //2. 创建缓存策略(强制缓存,对比缓存等策略);    CacheStrategy strategy = new CacheStrategy.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) {      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();    }    // 4. 根据策略,不使用网络,有缓存就直接返回;    // If we don't need the network, we're done.    if (networkRequest == null) {      return cacheResponse.newBuilder()          .cacheResponse(stripBody(cacheResponse))          .build();    }    Response networkResponse = null;    try {     // 5. 前面个都没有返回,读取网络结果(跑下一个拦截器);      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());      }    }   //6. 接收到的网络结果,如果是code 304, 使用缓存,返回缓存结果(对比缓存)    // 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());      }    }   //7. 读取网络结果;    Response response = networkResponse.newBuilder()        .cacheResponse(stripBody(cacheResponse))        .networkResponse(stripBody(networkResponse))        .build();    //8. 对数据进行缓存;    if (HttpHeaders.hasBody(response)) {      CacheRequest cacheRequest = maybeCache(response, networkResponse.request(), cache);      response = cacheWritingResponse(cacheRequest, response);    }    //9. 返回网络读取的结果。    return response;  }

总结

缓存实际上是一个比较复杂的逻辑,这里只是简单的对拦截器的功能进行了分析,并没有深入的分析其中的实现,但实际上缓存不属于okhttp上的功能,只是对http协议做了处理,整体其实是属于http相关的,而在okhttp中使用了拦截器的方式,进行了实现。

有兴趣的可以继续研究一下以下的点:

  1. 缓存策略是如何生成的,做了些什么判断
  2. 缓存是如何保存的

系列:
OKhttp源码学习(一)—— 基本请求流程
OKhttp源码学习(二)—— OkHttpClient
OKhttp源码学习(三)—— Request, RealCall
OKhttp源码学习(四)—— RetryAndFollowUpInterceptor拦截器
OKhttp源码学习(五)—— BridgeInterceptor拦截器
OKhttp源码学习(七)—— ConnectInterceptor拦截器
OKhttp源码学习(八)——CallServerInterceptor拦截器
OKhttp源码学习(九)—— 任务管理(Dispatcher)

文章转载于:https://www.jianshu.com/p/963ad9ca214d

原著是一个有趣的人,若有侵权,请通知删除

本博客所有文章如无特别注明均为原创。
复制或转载请以超链接形式注明转自起风了,原文地址《OKhttp源码学习(六)—— CacheInterceptor
   

还没有人抢沙发呢~