Android-Okhttp底層原理淺析(四)

啊,手廢了,廢了~
第一篇講的是同步、異步調(diào)用源碼走向Android-OKHTTP底層原理淺析(一)
第二篇講的是重定向攔截器、橋攔截器的工作內(nèi)容Android-OKHttp底層原理淺析(二)
第三篇講的是緩存攔截器、連接攔截器的工作內(nèi)容Android-OKhttp底層原理淺析(三)

開擼!CallServerInterceptor——呼叫服務(wù)攔截器

@Override public Response intercept(Chain chain) throws IOException {
    HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
    StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
    Request request = chain.request();

    long sentRequestMillis = System.currentTimeMillis();
    httpCodec.writeRequestHeaders(request);

    Response.Builder responseBuilder = null;
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
      // Continue" response before transmitting the request body. If we don't get that, return what
      // we did get (such as a 4xx response) without ever transmitting the request body.
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        responseBuilder = httpCodec.readResponseHeaders(true);
      }

      // Write the request body, unless an "Expect: 100-continue" expectation failed.
      if (responseBuilder == null) {
        Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
      }
    }

    httpCodec.finishRequest();

    if (responseBuilder == null) {
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();
    if (forWebSocket && code == 101) {
      // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }

    if ("close".equalsIgnoreCase(response.request().header("Connection"))
        || "close".equalsIgnoreCase(response.header("Connection"))) {
      streamAllocation.noNewStreams();
    }

    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
      throw new ProtocolException(
          "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
    }

    return response;
  }

pia,代碼出來了,來,扣
這里把之前兄弟們傳下來的數(shù)據(jù)都給拿了出來(都大結(jié)局了)httpCodec, streamAllocation, request

httpStream.writeRequestHeaders(request);

if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        responseBuilder = httpCodec.readResponseHeaders(true);
      }
      if (responseBuilder == null) {
        Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
      }
    }

上面代碼是寫入請求頭信息跟寫入請求體信息

httpCodec.finishRequest();

這里結(jié)束請求了

if (responseBuilder == null) {
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

接下來這里獲取響應(yīng)頭的信息

   Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

這里構(gòu)建了Response, 傳入原請求,握手的情況,請求的時間,接收到響應(yīng)的時間

if (forWebSocket && code == 101) {
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }

這里將body修改為空響應(yīng),或者是響應(yīng)體信息
最后就是返回response給上個攔截器了。
總結(jié)一下這邊所做的內(nèi)容就是

1,獲取一些從上層的各個攔截器處理完成后傳入的對象
2,寫入請求頭信息
3,寫入請求體信息
4,結(jié)束請求
5,讀取響應(yīng)頭信息
6,讀取響應(yīng)體信息或標(biāo)記為空響應(yīng)信息
7,判斷請求頭是否有close標(biāo)記,是則斷開連接
8,如果有協(xié)議異常,拋出
9,返回響應(yīng)數(shù)據(jù)至上層攔截器

這邊做的事情,其實很多都是上一個攔截器(ConnectInterceptor )已經(jīng)準(zhǔn)備好的,也有一些數(shù)據(jù)是一路傳了下來比如httpCodec, streamAllocation, request,在這邊主要是做了一個請求的發(fā)起以及數(shù)據(jù)的響應(yīng)。

ok,最后一個官方攔截器講完了,我為啥要說“官方”呢,因為這里還有我們可以自定義的攔截器,回到我們最初的攔截器集合代碼那里

List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

其中interceptors.addAll(client.interceptors())跟 interceptors.addAll(client.networkInterceptors())都是我們可以自行添加的,不同的是前后順序的區(qū)別,第一個

interceptors.addAll(client.interceptors())

是在請求發(fā)送前,以及網(wǎng)絡(luò)響應(yīng)后所執(zhí)行的攔截器,比如我們的HttpLoggingInterceptor攔截器,插入的就是這個位置

HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.BODY;
                    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
                        @Override
                        public void log(String message) {
                             Utils.logAll("OkHttpClient", message);
                        }
                    });
                    loggingInterceptor.setLevel(level);

                    okHttpClient = new OkHttpClient.Builder()
                            .cookieJar(new CookieJarImpl(new MemoryCookieStore()))
                            .addInterceptor(loggingInterceptor)
                            .build();

而如果插入到networkInterceptors這個位置呢,就有一定的區(qū)別,因為這是處于第六個攔截器,這時的請求已經(jīng)經(jīng)過了前面幾個攔截器的處理,比如重定向,請求跟響應(yīng)的處理等,這里可以得到更多的信息。當(dāng)然相反的,這里獲取到的響應(yīng)也是最初的(他是CallServerInterceptor的上一層),沒有經(jīng)過其他攔截器的響應(yīng)處理,是否需要這些數(shù)據(jù)就看各自的需求了。

好了,okhttp的底層原理暫時告一段落,其實里面的內(nèi)容真的很龐大,要一個一個點去深挖我覺得是很耗費(fèi)精力的,與其如此不如先把流程走透,學(xué)習(xí)他人的設(shè)計想法跟思路,這是我們提升自己代碼技巧最直觀最實際的做法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容