OkHttp面试之--HttpEngine中的sendRequest方法详解
Posted Danny_姜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OkHttp面试之--HttpEngine中的sendRequest方法详解相关的知识,希望对你有一定的参考价值。
上一节我们介绍了OkHttp网络异步请求的整个流程。其中在流程的最后阶段,我们发现最终创建了HttpEngine对象,并分别调用的此对象的sendRequest和readResponse方法。这两个方法 分别有它相应的作用。这一节我们着重来分析sendRequest流程。
以下是sendRequest的整个方法中的内容:
public void sendRequest() throws RequestException, RouteException, IOException {
if (cacheStrategy != null) return; // Already sent.
if (httpStream != null) throw new IllegalStateException();
Request request = networkRequest(userRequest);
InternalCache responseCache = Internal.instance.internalCache(client);
Response cacheCandidate = responseCache != null
? responseCache.get(request)
: null;
long now = System.currentTimeMillis();
cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
networkRequest = cacheStrategy.networkRequest;
cacheResponse = cacheStrategy.cacheResponse;
if (responseCache != null) {
responseCache.trackResponse(cacheStrategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
// If we're forbidden from using the network and the cache is insufficient, fail.
if (networkRequest == null && cacheResponse == null) {
userResponse = new Response.Builder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(EMPTY_BODY)
.build();
return;
}
// If we don't need the network, we're done.
if (networkRequest == null) {
userResponse = cacheResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.build();
userResponse = unzip(userResponse);
return;
}
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean success = false;
try {
httpStream = connect();
httpStream.setHttpEngine(this);
if (writeRequestHeadersEagerly()) {
long contentLength = OkHeaders.contentLength(request);
if (bufferRequestBody) {
if (contentLength > Integer.MAX_VALUE) {
throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
+ "setChunkedStreamingMode() for requests larger than 2 GiB.");
}
if (contentLength != -1) {
// Buffer a request body of a known length.
httpStream.writeRequestHeaders(networkRequest);
requestBodyOut = new RetryableSink((int) contentLength);
} else {
// Buffer a request body of an unknown length. Don't write request headers until the
// entire body is ready; otherwise we can't set the Content-Length header correctly.
requestBodyOut = new RetryableSink();
}
} else {
httpStream.writeRequestHeaders(networkRequest);
requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
}
}
success = true;
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (!success && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
}
可以看到sendRequest方法比较长,我对它进行分块解析。其中主要分以下两大块
1 先从 Cache 中判断当前请求是否可以从缓存中返回
2 如果没有Cache则连接网络
先来看下connect方法中是如何创建HttpStream对象的
调用SteamAllocation.newStream的方法创建HttpStream对象并返回。点进去代码如下所示:
从上图中可以看出,在newStream方法中先通过findHealthyConnection方法获取一个RealConnection对象,实际上就是查找可用的Socket对象。在OkHttp框架中有一个特点就是OkHttp可以使用一个Socket对象来维护拥有过个ip的Server端,对于Socket的实现后续再单独讲解,此处不再做介绍。
获取RealConnction对象之后,根据此对象再获取相应的HttpStream对象,我们一般返回的是Http1xStream对象,最后将resultStream赋值给全局变量stream。而这个全局变量会再下一节readResponse方法中再使用。
注意:本节主要对于sendRequest方法中比较核心的代码进行的跟踪分析,在此方法中还有对Request请求的Head和Body的添加操作并没有进行详细描述。感兴趣的同学可以自行研究。
下一节继续讲解HttpEngine.readResponse方法的流程
以上是关于OkHttp面试之--HttpEngine中的sendRequest方法详解的主要内容,如果未能解决你的问题,请参考以下文章