OK HTTP(二)Okhttp的缓存拦截器CacheInterceptor

Okhttp的缓存拦截器CacheInterceptor

  • okhttp 提供了 CacheInterceptor 来处理缓存
  • 关于如何使用缓存请参考缓存管理
  • 下面我们分析下该拦截器的工作流程

流程分析

  • 主要流程都在intercept 方法里 下面看代码
public final class CacheInterceptor implements Interceptor {
    final @Nullable
    // 注意观察 这里InternalCache
    InternalCache cache;
    @Override public Response intercept(Chain chain) throws IOException {
        // 1、读取候选缓存 如果缓存不为空 则获取缓存中 request 对应的 response
        Response cacheCandidate = cache != null
            ? cache.get(chain.request())
            : null;

        long now = System.currentTimeMillis();
        // 2、获取缓存策略 内部维护了 一个request  和一个 response
        // 该类作用 判断当前请求适用与网络或者缓存 或者两者都用(强制缓存、对比缓存)
        // networkRequest 代表网络请求
        // cacheResponse   代表使用缓存
        CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
        Request networkRequest = strategy.networkRequest;
        Response cacheResponse = strategy.cacheResponse;
        // 3、如果缓存不为空 更新统计指标, 增加命中率
        if (cache != null) {
          cache.trackResponse(strategy);
        }
        // 4、如果候选缓存不适用 则关闭该缓存响应
        // 候选缓存不为空 与 缓存策略为空(及不允许使用缓存) 来表示候选缓存无效
        if (cacheCandidate != null && cacheResponse == null) {
          closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
        }

        // 5、根据策略进行判断  如果禁止使用网络 但是缓存也没有 则构建response返回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();
        }

        // 6、根据策略 如果不允许使用网络,有缓存的 直接返回 缓存中的response
        if (networkRequest == null) {
          return cacheResponse.newBuilder()
              .cacheResponse(stripBody(cacheResponse))
              .build();
        }
        //7、如果允许使用网络 则 进行网络请求
        Response networkResponse = null;
        try {
          networkResponse = chain.proceed(networkRequest);
        } finally {
          // 如果出现io 异常 同时 预选缓存不为空 则直接关闭最新的
          if (networkResponse == null && cacheCandidate != null) {
            closeQuietly(cacheCandidate.body());
          }
        }

        // 8、如果缓存不为空 则判断最新获取的networkresponse的code
        // 是不是等于 HTTP_NOT_MODIFIED 304 如果是则使用缓存 并更新缓存
        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());
          }
        }
        //9、 如果缓存response为空则读取网络请求response
        Response response = networkResponse.newBuilder()
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        // 10、 如果cache不为空 且满足缓存条件 - 存在body 与 策略可缓存 则缓存response
        if (cache != null) {
          if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
            // Offer this request to the cache.
            CacheRequest cacheRequest = cache.put(response);
            return cacheWritingResponse(cacheRequest, response);
          }
        // 11、 判断是否get请求 不是则直接 在缓存中移除当前请求
          if (HttpMethod.invalidatesCache(networkRequest.method())) {
            try {
              cache.remove(networkRequest);
            } catch (IOException ignored) {
              // The cache cannot be written.
            }
          }
        }
        12、 最后返回response
        return response;
      }
  }

流程总结

    1. 首先判断缓存是否为空,不为空,获取预选缓存的resposne
    2. 获取一个CacheStrategy 缓存策略对象(此处是一个重点)
      • 该类主要是用于解决到底使用网络还是缓存,亦或是两者皆用
      • 缓存策略的获取请参看缓存策略获取
    3. 判断预选缓存response是否有效若无效则关闭预选缓存response
      • 判断条件
        • 存在预选缓存且缓存策略中不允许使用缓存就表示预选缓存无效
    4. 根据缓存策略判断如果不允许使用网络且缓存策略也没有,构建response设置code504 并返回
    5. 根据缓存策略判断如果不允许使用网络请求且存在缓存 则直接返回缓存的response
    6. 如果允许使用网络则获取网络响应,判断缓存response是否为空
      • 如果不为空,则判断最新获取的response的code是否为304(304 表示数据没发生变化)
        • 是 则返回缓存response 并更新缓存
        • 否 则关闭缓存response
      • 如果为空,顺序执行,读取网络请求的response
    7. ,判断缓存Cache是否为空(此处开始后面则有缓存逻辑)
      • 若为空则不处理
      • 若不为空则判断该request 是否满足缓存条件
        • 若满足,则缓存该次请求 并返回此次网络请求的响应response
        • 若不满足,则不处理,
      • 判断是否get请求 若不是则在缓存中直接移除此次请求
    8. 返回读取到的网络请求的response

缓存拦截器作用总结

  • 根据策略完成数据的缓存和读取

  • 根据获取到的缓存策略决定从哪读取respnse(网络或者缓存或者对比数据)并返回response给上一个拦截器

  • 调用proceed方法执行下一个拦截器 ->ConnectionInterceptor

注意

  • 在 CacheInterceptor类里我们看到存在一个 InternalCache 的对象cache 且为final 并不允许为空
    • 并在后面缓存数据的时候是通过cache.put
    • 猜测 这个InternalCache 就是用来 对数据进行系列缓存操作的
  • 这是什么,用来做什么 ?
    • InternalCache 是一个缓存内部接口
    • 为缓存类Cache 提供增删改查的方法供外界使用 在缓存管理里会提到
后续的是ConnectInterceptor和CallServerInterceptor看下面连接的内容

OkHttp(三)拦截器之ConnectionInterceptor 与CallServerInterceptor

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值