OkHttp面试之--HttpEngine中的readResponse流程简介

    xiaoxiao2021-08-22  72

    上一节主要大体看了一下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对象中返回

    转载请注明原文地址: https://ju.6miu.com/read-676903.html

    最新回复(0)