OkHttp源碼解讀總結(十)--->CacheInterceptor攔截器

OkHttp源碼解讀總結(十)—>CacheInterceptor攔截器

標籤(空格分隔): OkHttp源碼 學習筆記


前言

  • 以下的相關知識總結是通過慕課網的相關學習和自己的相關看法,如果有需要的可以去查看一下慕課網的相關教學,感覺還可以。

前面總結了Cache的get(讀)和put(取)方法,HTTP的緩存的工作是通過一個叫CacheInterceptor攔截器來完成的

源碼解讀

@Override public Response intercept(Chain chain) throws IOException {
    //1、如果配置緩存  則讀取緩存,不保證存在
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;
    //當前時間
    long now = System.currentTimeMillis();
    //緩存策略  內部維護了一個request和一個response  內部可以指定 是通過網絡(request)  還是通過緩存(response) 還是通過兩者一起 去獲取response
    //通過CacheStrategy.Factory的工廠類的get方法獲取這個緩存策略   (1)標註
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    //獲取request
    Request networkRequest = strategy.networkRequest;
    Response cacheResponse = strategy.cacheResponse;
    //判斷是否有緩存
    if (cache != null) {
      //當有緩存的時候  更新緩存指標  這個我們要實現的話 是實現的okhttp3.cache裏面的方法
      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) {
      //通過構建者模式創建一個Response響應  拋出504錯誤
      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.
    //如果有緩存 但是不能使用網絡  直接返回緩存結果
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }
   //
    Response networkResponse = null;
    try {
      //通過調用proceed()方法進行網絡的數據獲取 並且交給下一個攔截器進行獲取(ConnectInterceptor攔截器)
      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) {
      //判斷響應碼是否是HTTP_NOT_MODIFIED = 304   從緩存中讀取數據
      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);
        //緩存到本地
        return cacheWritingResponse(cacheRequest, response);
      }
      //判斷這個方法是否是無效的緩存方法
      if (HttpMethod.invalidatesCache(networkRequest.method())) {
        try {
        // 刪除
          cache.remove(networkRequest);
        } catch (IOException ignored) {
          // The cache cannot be written.
        }
      }
    }

    return response;
  }

CacheStrategy.Factory.get()方法

 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;
    }

getCandidate()方法

 /** Returns a strategy to use assuming the request can use the network. */
    private CacheStrategy getCandidate() {
      // No cached response.  沒有response
      if (cacheResponse == null) {
      //重新創建一個網絡請求   
        return new CacheStrategy(request, null);
      }

      // Drop the cached response if it's missing a required handshake.
      //請求是否是https  並且這個請求是否經歷過握手(handshake()操作)
      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 check should be redundant as long as the
      // persistence store is well-behaved and the rules are constant.
      //判斷這個響應是否要進行存儲
      if (!isCacheable(cacheResponse, request)) {
        //如果不存儲 則重新網絡請求
        return new CacheStrategy(request, null);
      }
     //
      CacheControl requestCaching = request.cacheControl();
      //如果我們指定了不進行網絡緩存   並且請求是可選擇
      if (requestCaching.noCache() ||  hasConditions(request)) {
        //重新網絡請求
        return new CacheStrategy(request, null);
      }
     //
      CacheControl responseCaching = cacheResponse.cacheControl();
      //
      if (responseCaching.immutable()) {

        return new CacheStrategy(null, cacheResponse);
      }

      long ageMillis = cacheResponseAge();
      long freshMillis = computeFreshnessLifetime();

      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\"");
        }
        //最終返回
        return new CacheStrategy(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;
      } else if (lastModified != null) {
        conditionName = "If-Modified-Since";
        conditionValue = lastModifiedString;
      } else if (servedDate != null) {
        conditionName = "If-Modified-Since";
        conditionValue = servedDateString;
      } else {
        return new CacheStrategy(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();
      return new CacheStrategy(conditionalRequest, cacheResponse);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章