OkHttp面試之--HttpEngine中的readResponse流程簡介

來源:互聯網
上載者:User

標籤:key   pen   host   hid   wrap   already   cee   send   address   

上一節主要大體看了一下sendRequest的流程,本節來看一下當請求發送出去之後,是如果讀取請求體中的資料的,具體的代碼都在HttpEngine.readResponse方法中,代碼如下:

public void readResponse() throws IOException {    if (userResponse != null) {      return; // Already ready.    }    if (networkRequest == null && cacheResponse == null) {      throw new IllegalStateException("call sendRequest() first!");    }    if (networkRequest == null) {      return; // No network response to read.    }    Response networkResponse;    if (forWebSocket) {      httpStream.writeRequestHeaders(networkRequest);      networkResponse = readNetworkResponse();    } else if (!callerWritesRequestBody) {      networkResponse = new NetworkInterceptorChain(0, networkRequest).proceed(networkRequest);    } else {      // Emit the request body‘s buffer so that everything is in requestBodyOut.      if (bufferedRequestBody != null && bufferedRequestBody.buffer().size() > 0) {        bufferedRequestBody.emit();      }      // Emit the request headers if we haven‘t yet. We might have just learned the Content-Length.      if (sentRequestMillis == -1) {        if (OkHeaders.contentLength(networkRequest) == -1            && requestBodyOut instanceof RetryableSink) {          long contentLength = ((RetryableSink) requestBodyOut).contentLength();          networkRequest = networkRequest.newBuilder()              .header("Content-Length", Long.toString(contentLength))              .build();        }        httpStream.writeRequestHeaders(networkRequest);      }      // Write the request body to the socket.      if (requestBodyOut != null) {        if (bufferedRequestBody != null) {          // This also closes the wrapped requestBodyOut.          bufferedRequestBody.close();        } else {          requestBodyOut.close();        }        if (requestBodyOut instanceof RetryableSink) {          httpStream.writeRequestBody((RetryableSink) requestBodyOut);        }      }      networkResponse = readNetworkResponse();    }    receiveHeaders(networkResponse.headers());    // If we have a cache response too, then we‘re doing a conditional get.    if (cacheResponse != null) {      if (validate(cacheResponse, networkResponse)) {        userResponse = cacheResponse.newBuilder()            .request(userRequest)            .priorResponse(stripBody(priorResponse))            .headers(combine(cacheResponse.headers(), networkResponse.headers()))            .cacheResponse(stripBody(cacheResponse))            .networkResponse(stripBody(networkResponse))            .build();        networkResponse.body().close();        releaseStreamAllocation();        // Update the cache after combining headers but before stripping the        // Content-Encoding header (as performed by initContentStream()).        InternalCache responseCache = Internal.instance.internalCache(client);        responseCache.trackConditionalCacheHit();        responseCache.update(cacheResponse, stripBody(userResponse));        userResponse = unzip(userResponse);        return;      } else {        closeQuietly(cacheResponse.body());      }    }    userResponse = networkResponse.newBuilder()        .request(userRequest)        .priorResponse(stripBody(priorResponse))        .cacheResponse(stripBody(cacheResponse))        .networkResponse(stripBody(networkResponse))        .build();    if (hasBody(userResponse)) {      maybeCache();      userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));    }  }

從開始進行分析

此處的userResponse在第一次訪問時是null的,因此不會進入此代碼塊,實際會進入如下判斷語句塊中

可以看到此處又調用了一個串連攔截器,對請求結果進行攔截,NetworkInterceptorChain也是實現了Intercept.Chain, 具體代碼

class NetworkInterceptorChain implements Interceptor.Chain {    private final int index;    private final Request request;    private int calls;    NetworkInterceptorChain(int index, Request request) {      this.index = index;      this.request = request;    }    @Override public Connection connection() {      return streamAllocation.connection();    }    @Override public Request request() {      return request;    }    @Override public Response proceed(Request request) throws IOException {      calls++;      if (index > 0) {        Interceptor caller = client.networkInterceptors().get(index - 1);        Address address = connection().route().address();        // Confirm that the interceptor uses the connection we‘ve already prepared.        if (!request.url().host().equals(address.url().host())            || request.url().port() != address.url().port()) {          throw new IllegalStateException("network interceptor " + caller              + " must retain the same host and port");        }        // Confirm that this is the interceptor‘s first call to chain.proceed().        if (calls > 1) {          throw new IllegalStateException("network interceptor " + caller              + " must call proceed() exactly once");        }      }      if (index < client.networkInterceptors().size()) {        // There‘s another interceptor in the chain. Call that.        NetworkInterceptorChain chain = new NetworkInterceptorChain(index + 1, request);        Interceptor interceptor = client.networkInterceptors().get(index);        Response interceptedResponse = interceptor.intercept(chain);        // Confirm that the interceptor made the required call to chain.proceed().        if (chain.calls != 1) {          throw new IllegalStateException("network interceptor " + interceptor              + " must call proceed() exactly once");        }        if (interceptedResponse == null) {          throw new NullPointerException("network interceptor " + interceptor              + " returned null");        }        return interceptedResponse;      }      httpStream.writeRequestHeaders(request);      //Update the networkRequest with the possibly updated interceptor request.      networkRequest = request;      if (permitsRequestBody(request) && request.body() != null) {        Sink requestBodyOut = httpStream.createRequestBody(request, request.body().contentLength());        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);        request.body().writeTo(bufferedRequestBody);        bufferedRequestBody.close();      }      Response response = readNetworkResponse();      int code = response.code();      if ((code == 204 || code == 205) && response.body().contentLength() > 0) {        throw new ProtocolException(            "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());      }      return response;    }  }

主要來看下proceed方法

同樣還是一個迴圈遞迴調用,因此代碼其實在最後一層還是會調用一下代碼

具體每一行代碼的作用在圖片中已經做了簡單介紹。我們重點來看一下最重要的讀取請求結果的方法–readNetworkResponse,代碼如下:

到這我們就已經完成了從發送網路請求到讀取請求結果的流程,簡單總結一下在HttpEngine中兩個方法的工作
sendRequest–尋找合適的Socket對象並封裝在HttpStream中
readResponse–通過HttpStream發送請求,並讀取結果封裝到Response對象中返回

OkHttp面試之--HttpEngine中的readResponse流程簡介

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.