okHttp源码解析-4 缓存拦截器 CacheInterceptor

缓存拦截器就是处理缓存数据,这个思路上不复杂,如果你们配置使用缓存数据,就会根据缓存策略判断是否能使用缓存的数据,如果可以就取缓存的数据,否则,则去请求网络。

1.CacheInterceptor

  @Override public Response intercept(Chain chain) throws IOException {
 /** 首先判断缓存对象是否为null,非空就获取缓存对象,否则null,且给Response 赋值
  *cache对象是谁, InternalCache cache; 由当前缓存拦截器构造的时候传入。*InternalCache 是个接口,所以去看实现类,但是实现类没有,但是在okhttp3.Cache里找
  *到了InternalCache 的内部类实例,同时还重写相应的方法。get put remove update等方法。
  下面细讲
  */
    Response cacheCandidate = cache != null ? cache.get(chain.request())  : null;

    long now = System.currentTimeMillis();
//CacheStrategy 缓存策略对象,工厂模式,最后get()获取
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    Request networkRequest = strategy.networkRequest;
    Response cacheResponse = strategy.cacheResponse;

    if (cache != null) {
      cache.trackResponse(strategy);
    }

//缓存对象不为空,但是缓存的响应对象null,关闭缓存
    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.
    // 网络请求对象null 缓存对象null 直接返回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 we don't need the network, we're done.
    // 请求对象为null,返回缓存的对象,该对象是null的body对象,
    //stripBody方法去除了body
    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.
    // 如果缓存对象不为空,且返回304-重定向无修改数据,合并缓存的header和网络的header
    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();
	// 判断是否有body
    if (HttpHeaders.hasBody(response)) {
    	// 判断是否请求方法合法,因为缓存只处理GET请求,不合法从缓存对象移除
      CacheRequest cacheRequest = maybeCache(response, networkResponse.request(), cache);
      // 写入响应对象到缓存
      response = cacheWritingResponse(cacheRequest, response);
    }

    return response;
  }

2.缓存底层实现

okHttp使用InternalCache cache实现缓存数据的处理。

/**
 * OkHttp's internal cache interface. Applications shouldn't implement this: instead use {@link
 * okhttp3.Cache}.
 */
public interface InternalCache

是个接口,请查阅okhttp3.Cache

  final InternalCache internalCache = new InternalCache() {
    @Override public Response get(Request request) throws IOException {
      return Cache.this.get(request);
    }

    @Override public CacheRequest put(Response response) throws IOException {
      return Cache.this.put(response);
    }

    @Override public void remove(Request request) throws IOException {
      Cache.this.remove(request);
    }

    @Override public void update(Response cached, Response network) {
      Cache.this.update(cached, network);
    }

    @Override public void trackConditionalCacheHit() {
      Cache.this.trackConditionalCacheHit();
    }

    @Override public void trackResponse(CacheStrategy cacheStrategy) {
      Cache.this.trackResponse(cacheStrategy);
    }
  };

2.1 put 保存数据

 @Nullable CacheRequest put(Response response) {
 //请求方法
    String requestMethod = response.request().method();
//验证缓存的有效期
    if (HttpMethod.invalidatesCache(response.request().method())) {
      try {
        remove(response.request());
      } catch (IOException ignored) {
        // The cache cannot be written.
      }
      return null;
    }
  //  非get方法不缓存
    if (!requestMethod.equals("GET")) {
      // Don't cache non-GET responses. We're technically allowed to cache
      // HEAD requests and some POST requests, but the complexity of doing
      // so is high and the benefit is low.
      return null;
    }

    if (HttpHeaders.hasVaryAll(response)) {
      return null;
    }

//Entry是包装了所有响应的信息体,
    Entry entry = new Entry(response);
    DiskLruCache.Editor editor = null;
    try {
   //通过url作为key
      editor = cache.edit(key(response.request().url()));
      if (editor == null) {
        return null;
      }
      //写入到磁盘缓存里
      entry.writeTo(editor);
      return new CacheRequestImpl(editor);
    } catch (IOException e) {
      abortQuietly(editor);
      return null;
    }
  }

2.2 Entry

  private static final class Entry {
    /** Synthetic response header: the local time when the request was sent. */
    private static final String SENT_MILLIS = Platform.get().getPrefix() + "-Sent-Millis";

    /** Synthetic response header: the local time when the response was received. */
    private static final String RECEIVED_MILLIS = Platform.get().getPrefix() + "-Received-Millis";

    private final String url;
    private final Headers varyHeaders;
    private final String requestMethod;
    private final Protocol protocol;//协议
    private final int code;
    private final String message;
    private final Headers responseHeaders; //响应头部
    private final @Nullable Handshake handshake;// 握手
    private final long sentRequestMillis;
    private final long receivedResponseMillis;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值