1. 程式人生 > >OKHttp原始碼分析-BridgeInterceptor

OKHttp原始碼分析-BridgeInterceptor

在上一篇部落格中我們介紹了一下RetryAndFollowUpInterceptor攔截器內容也是比較多的這次我們先介紹個簡單的攔截器BridgeInterceptor,這個攔截器的主要作用就是對請求引數做一下處理內容也是很簡單我們直接上原始碼。
BridgeInterceptor三步走策略

1. 取出請求頭判斷標頭檔案缺失內容如果沒有則補充上
2. 呼叫 chain.proceed方法吧請求交給下一個攔截器去處理
3. 取出響應體對返回資料進行簡單封裝返回給上一級攔截器

@Override public Response intercept(Chain chain) throws IOException {
    Request userRequest =
chain.request(); Request.Builder requestBuilder = userRequest.newBuilder(); RequestBody body = userRequest.body(); if (body != null) { MediaType contentType = body.contentType(); if (contentType != null) { requestBuilder.header("Content-Type", contentType.toString()); } long contentLength =
body.contentLength(); if (contentLength != -1) { requestBuilder.header("Content-Length", Long.toString(contentLength)); requestBuilder.removeHeader("Transfer-Encoding"); } else { requestBuilder.header("Transfer-Encoding", "chunked"); requestBuilder.removeHeader("Content-Length"
); } } if (userRequest.header("Host") == null) { requestBuilder.header("Host", hostHeader(userRequest.url(), false)); } // 這個頭資訊必須要,但是使用者不一定會自己設定 if (userRequest.header("Connection") == null) { requestBuilder.header("Connection", "Keep-Alive"); } // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing // the transfer stream. boolean transparentGzip = false; if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) { transparentGzip = true; requestBuilder.header("Accept-Encoding", "gzip"); } List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url()); if (!cookies.isEmpty()) { requestBuilder.header("Cookie", cookieHeader(cookies)); } if (userRequest.header("User-Agent") == null) { requestBuilder.header("User-Agent", Version.userAgent()); } // 下一級給我們的 Response Response networkResponse = chain.proceed(requestBuilder.build()); // 處理儲存 Cookie HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers()); Response.Builder responseBuilder = networkResponse.newBuilder() .request(userRequest); // 如果後臺返回的資料採用 gzip 壓縮了 if (transparentGzip && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding")) && HttpHeaders.hasBody(networkResponse)) { // GzipSource okio 的輸入流 GzipSource responseBody = new GzipSource(networkResponse.body().source()); Headers strippedHeaders = networkResponse.headers().newBuilder() .removeAll("Content-Encoding") .removeAll("Content-Length") .build(); responseBuilder.headers(strippedHeaders); String contentType = networkResponse.header("Content-Type"); responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody))); } // 我們這個攔截器處理的 Response 返回回去 return responseBuilder.build(); }

這塊的邏輯比起上一個攔截器來說要簡化了不少啊,我們依然逐行分析

    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();
    RequestBody body = userRequest.body();

這段程式碼意思是從我們的攔截器裡面取出請求然後從請求中取出請求體RequestBody 然後對RequestBody 進行校驗。

RequestBody body = userRequest.body();
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }
    }

    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }
    // 這個頭資訊必須要,但是使用者不一定會自己設定
    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }

    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }

上面一大段都是校驗判斷我們的請求頭有沒有必須要有的資訊如果沒有則在requestBuilder中新增header,這麼做的目的是為了防止我們沒有設定某些請求頭而報錯。

    // 下一級給我們的 Response
    Response networkResponse = chain.proceed(requestBuilder.build());

接下來還是呼叫了 chain.proceed方法將任務交給下一級去處理等處理完了之後再繼續處理下面的內容

// 處理儲存 Cookie
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);
    // 如果後臺返回的資料採用 gzip 壓縮了
    if (transparentGzip
        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
        && HttpHeaders.hasBody(networkResponse)) {
      // GzipSource okio 的輸入流
      GzipSource responseBody = new GzipSource(networkResponse.body().source());
      Headers strippedHeaders = networkResponse.headers().newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build();
      responseBuilder.headers(strippedHeaders);
      String contentType = networkResponse.header("Content-Type");
      responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
    }
    // 我們這個攔截器處理的 Response 返回回去
    return responseBuilder.build();

HttpHeaders.receiveHeaders這一段沒啥好解釋的就是將請求處理好的cookie儲存到本地,後面的處理時如果後臺返回的資料被採用GZIP壓縮了那麼使用OKIO將responseBody解壓轉換為流封裝到RealResponseBody中去,最後呼叫responseBuilder.build()將請求返回。