標籤: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流程簡介