OkHttp面试之--HttpEngine中的readResponse流程简介
Posted Danny_姜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OkHttp面试之--HttpEngine中的readResponse流程简介相关的知识,希望对你有一定的参考价值。
上一节主要大体看了一下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流程简介的主要内容,如果未能解决你的问题,请参考以下文章