一、前言
一直以来都想找个时间看看OKHTTP的源码,最近抽空研究了下,以此记录下对OKHTTP源码的研究成果,当然,网上有很多关于写的很牛逼的博客。我就不和他们比了,谨以此记录一下我的心路历程。
说明:这篇博客是以OKHTTP3.3.1为研究对象,高版本的我也大概看了一下,改动还是有点大的,这里只讲3.3.1版本的。我这里对OKHTTP3.3.1的流程、框架进行梳理。
二、概述
OKHTTP3.3.1版本,主要的几个核心类为:
类名 | 描述 | 类比说明 |
---|---|---|
OkHttpClient | 主要涉及OKHTTP内部一些类的初始化,和参数的设置。用户可以拿到OKHTTP的引用进行设置一些用户网络访问的一些参数。 | 类比于一个咖啡厅的服务员,接受用户请求,自己不做处理,而是分发给下一层。 |
ReallCall | 处理用户请求,并返回响应结果给用户的类 | 类比于咖啡机的按键,接受服务员请求,给内部机器处理,然后自己得到结果给服务员 |
Dispatcher | 请求事件处理分发类,将请求事件分为正在执行的请求(runningAsyncCalls)和 准备执行的请求(readyAsyncCalls) | 咖啡机内部机器接收到指令后,进行执行指令操作,一次只能执行6个指令(runningAsyncCalls),多余的等待(readyAsyncCalls) |
ApplicationInterceptorChain | 拦截器链,存在于Realcall内部, | 咖啡机内部的一条监控程序(分析程序),贯穿整个生产过程,在机器运行过程中,通过拦截,获取拦截处的样品,分析并将结果返还给用户 |
HttpEngine | 网络请求引擎,负责网络连接任务的分发,请求响应数据打包压缩给上层 | 咖啡机内部将上层过来的指令分发给具体的生产咖啡的执行模块,而自己负责给生产完成的咖啡做最后的处理(加糖、加奶),并装入纸杯中 |
StreamAllocation | 发送socket连接远端服务器请求并返回一个HttpSteam给上层 | |
RealConnection | socket连接服务器实际执行的类,该类将一些必要的数据参数传递给底层,然后进行相应的操作 |
说明:以上这些类是我个人认为是OKHTTP的核心类。其中说明下,在高版本的OKHTTP源码中,设计者已对代码进行了一些改动,其中HttpEngine类被分解,ApplicationInterceptorChain类被移除,取而代之的是多个内置的拦截器,层层执行,并将最终结果返回给调用者。
三、源码流程讲解
前置:整个流程讲解围绕我们使用方式为入口。
3.1 OKHTTP的使用方式
说明:OKHTTP有两种调用方式:1、同步调用 2、异步调用
3.1.1 同步调用方式
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.build();
client.newCall(request).execute();
- 1
- 2
- 3
- 4
- 5
3.1.2 异步调用方式
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
说明:同步请求为当前线程只能执行一个请求,而异步则不同,由于其内部有一个线程池执行请求,所以异步可以执行多个。同步和异步单条请求内部的实现方式都一样,下面就围绕异步请求来讲。
3.2 OKHTTP异步请求流程讲解
3.2.1 client.newCall(request)
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return new RealCall(this, request);
}
- 1
- 2
- 3
- 4
- 5
- 6
说明:该方法实际上是创建一个RealCall的实例,并将Request的的实例作为参数传入RealCall类中
3.2.2 realcall.enqueue(CallBack callback)
//异步请求
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//核心方法,两个操作。1、dispatcher.enqueue()分发请求,并执行 2、用户传入的request对象转换成AsyncCall对象
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
我们首先看下client.dispatcher().enqueue()这个方法的内部执行
//假如正在执行的异步回调小于maxRequests 64 对单个host请求数小于5,则将新的回调添加到runningAsyncCalls,否则将该新的请求添加到异步执行的队列中
synchronized void enqueue(RealCall.AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//runningAsyncCalls 正在执行的异步请求队列
runningAsyncCalls.add(call);
//线程池执行线程,实际调用的是AsyncCall中的execute()方法
executorService().execute(call); //executorService 线程池
} else {
//readyAsyncCalls准备执行的异步请求队列
readyAsyncCalls.add(call);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
再看new AsyncCall(responseCallback, forWebSocket)
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private final boolean forWebSocket;
private AsyncCall(Callback responseCallback, boolean forWebSocket) {
super("OkHttp %s", redactedUrl().toString());
this.responseCallback = responseCallback;
this.forWebSocket = forWebSocket;
}
----此处代码省略----
//网络请求的入口,diapather线程池执行最终调用的是该方法
@Override
protected void execute() {
boolean signalledCallback = false;
try {
//获得网络请求及拦截链返回的响应数据
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
//请求成功,将响应数据返回给上层
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(Platform.INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//每次执行完必定要走这里,该方法实际上是循环执行网络请求,类似于for循环,这种写法非常有意思。
client.dispatcher().finished(this);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
再看下client.dispatcher().finished(this)这个方法
/** Used by {@code AsyncCall#run} to signal completion. */
synchronized void finished(RealCall.AsyncCall call) {
if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
promoteCalls();
}
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
//轮询待执行的请求,并将待执行的请求加入到正在执行的队列中,然后执行线程
for (Iterator<RealCall.AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
RealCall.AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
到此,我们一个请求,从发送到执行再到返回数据,这整个流程就这样说完了。咳咳!这只是冰山一角,下面我们就深入它的内部执行。上面说到OKHTTP的同步和异步调用本质的内部实现方法是一样的,都执行了Response response = getResponseWithInterceptorChain(forWebSocket)这个方法,下面我们看下和这个方法的内部执行。
private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}
- 1
- 2
- 3
- 4
说明:ApplicationInterceptorChain类是RealCall的内部类,维护整个Application的拦截器链,最后调用chain.proceed(originalRequest)方法,下面看下该方法的具体实现代码如下:
class ApplicationInterceptorChain implements Interceptor.Chain {
private final int index;
private final Request request;
private final boolean forWebSocket;
ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
this.index = index;
this.request = request;
this.forWebSocket = forWebSocket;
}
-----代码省略-----
@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
//这里获得下一个的ApplicationInterceptorChain 主要是index的值每次执行一个拦截器 +1
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
//获得当前的拦截器
Interceptor interceptor = client.interceptors().get(index);
//这里开始执行下一个拦截器。自定义拦截器会实现Interceptor(示例代码下面会贴出)
Response interceptedResponse = interceptor.intercept(chain);
if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor
+ " returned null");
}
return interceptedResponse;
}
// No more interceptors. Do HTTP.(如果没有其他的拦截器,则执行HTTP请求)
//这里是关键
return getResponse(request, forWebSocket);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
拦截器示例代码,以自定义HostSelectionInterceptor 为例
public static final class HostSelectionInterceptor implements Interceptor {
//上面提到的interceptor.intercept(chain);它实际调用的是以下方法
@Override
public Response intercept(Chain chain) throws IOException {
// chain.proceed(chain.request()),该方法执行调用会执行下一个拦截器.
//如此循环,直到所有的拦截器走完,然后执行HTTP请求
return chain.proceed(chain.request());
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
3.3 OKHTTP的HTTP请求流程
当所有的拦截器都执行完之后,就开始执行HTTP请求了,方法为:getResponse(request, forWebSocket),其实现代码如下:
Response getResponse(Request request, boolean forWebSocket) throws IOException {
//......代码省略......
// Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
//HttpEngine 重试或者重定向都需要一个HTTPEngin
engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);
int followUpCount = 0; //重定向的数目
while (true) {
if (canceled) {
//HttpEngine释放连接池
engine.releaseStreamAllocation();
throw new IOException("Canceled");
}
boolean releaseConnection = true;
try {
//发送请求,本地socket与远程服务器进行连接
engine.sendRequest();
//读取服务器返回的响应数据
engine.readResponse();
releaseConnection = false;
} catch (RequestException e) {
//....代码省略....
}
// Give up; recovery is not possible.
throw e;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
StreamAllocation streamAllocation = engine.close();
streamAllocation.release();
}
}
//获得响应数据
Response response = engine.getResponse();
//获得重定向请求的Request 数据
Request followUp = engine.followUpRequest();
if (followUp == null) {
if (!forWebSocket) {
engine.releaseStreamAllocation();
}
return response;
}
StreamAllocation streamAllocation = engine.close();
if (++followUpCount > HttpEngine.MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (!engine.sameConnection(followUp.url())) {
streamAllocation.release();
streamAllocation = null;
} else if (streamAllocation.stream() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
//按照HttpEngine 的定义,每个重连或者重定向的连接,都需要新建一个httpEngine
engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
response);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
说明:上一段代码中有四个方法为核心方法,如下:
核心方法 | 说明 |
---|---|
engine.sendRequest() | 发送请求,本地socket与远程服务器进行连接 |
engine.readResponse() | 读取服务器返回的响应数据 |
engine.getResponse() | 获得服务器返回的响应数据 |
engine.followUpRequest() | 重定向的请求数据 |
下面我以此讲解四个方法的实现
3.3.1 engine.sendRequest() 发送连接请求
public void sendRequest() throws RequestException, RouteException, IOException {
if (cacheStrategy != null) return; // Already sent.
if (httpStream != null) throw new IllegalStateException();
//设置网络请求所需的字段cookeis、headers等字段
Request request = networkRequest(userRequest);
//初始化一个内部的缓存
InternalCache responseCache = Internal.instance.internalCache(client);
//cacheCandidate 缓存中的响应数据
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)
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.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 {
//Socket连接
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());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
说明:这段代码分两个部分讲解,由分割线分为上下两个部分,其中上半部分涉及缓存策略,而下半部分涉及http请求的连接。
1、上半部分,缓存
if (cacheStrategy != null) return; // Already sent.
//-------代码省略------
//cacheCandidate 缓存中的响应数据
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;
//-------代码省略------
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
首先看下 responseCache.get(request)这个方法实现,它最终调用的是Cache类中的get(Request request)方法
Response get(Request request) {
//将请求的URl进行MD5加密处理
String key = urlToKey(request);
//Snapshot 快照,存储每一个请求的cache在特定时刻的内容
DiskLruCache.Snapshot snapshot;
Entry entry;
try {
snapshot = cache.get(key); //根据请求中的URl的MD5码获得snapshot(快照),里面主要是对日志文件进行操作
if (snapshot == null) {
return null;
}
} catch (IOException e) {
// Give up because the cache cannot be read.
return null;
}
try {
//Entry 每一个请求的缓存对应一个Entry
entry = new Entry(snapshot.getSource(ENTRY_METADATA));
} catch (IOException e) {
Util.closeQuietly(snapshot);
return null;
}
//快照缓存中的响应数据
Response response = entry.response(snapshot);
if (!entry.matches(request, response)) {
Util.closeQuietly(response.body());
return null;
}
return response;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
下面再看下CacheStrategy.Factory(now, request, cacheCandidate).get()这个方法,获取缓存策略。
public CacheStrategy get() {
//获取缓存策略,我们再看下getCandidate()的具体实现,代码如下
CacheStrategy candidate = getCandidate();
if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
// We're forbidden from using the network and the cache is insufficient.
return new CacheStrategy(null, null);
}
return candidate;
}
/** Returns a strategy to use assuming the request can use the network. */
private CacheStrategy getCandidate() {
// No cached response.
if (cacheResponse == null) {
return new CacheStrategy(request, null);
}
// Drop the cached response if it's missing a required handshake.
//假如请求方式是HTTPs,但是handshake为空,则丢弃缓存响应
if (request.isHttps() && cacheResponse.handshake() == null) {
return new CacheStrategy(request, null);
}
//如果缓存不能被保存,则放弃缓存响应
if (!isCacheable(cacheResponse, request)) {
return new CacheStrategy(request, null);
}
CacheControl requestCaching = request.cacheControl();
//如果请求参数中设置了on-cache,那么放弃缓存
if (requestCaching.noCache() || hasConditions(request)) {
return new CacheStrategy(request, null);
}
long ageMillis = cacheResponseAge();
long freshMillis = computeFreshnessLifetime();
if (requestCaching.maxAgeSeconds() != -1) {
freshMillis = Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds()));
}
long minFreshMillis = 0;
if (requestCaching.minFreshSeconds() != -1) {
minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds());
}
long maxStaleMillis = 0;
CacheControl responseCaching = cacheResponse.cacheControl();
if (!responseCaching.mustRevalidate() && requestCaching.maxStaleSeconds() != -1) {
maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds());
}
//假如缓存数据的保存时间在数据的保鲜时间范围内,则直接拿取缓存数据
if (!responseCaching.noCache() && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) {
Response.Builder builder = cacheResponse.newBuilder();
if (ageMillis + minFreshMillis >= freshMillis) {
builder.addHeader("Warning", "110 HttpURLConnection \"Response is stale\"");
}
long oneDayMillis = 24 * 60 * 60 * 1000L;
if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) {
builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\"");
}
return new CacheStrategy(null, builder.build());
}
Request.Builder conditionalRequestBuilder = request.newBuilder();
if (etag != null) {
conditionalRequestBuilder.header("If-None-Match", etag);
} else if (lastModified != null) {
conditionalRequestBuilder.header("If-Modified-Since", lastModifiedString);
} else if (servedDate != null) {
conditionalRequestBuilder.header("If-Modified-Since", servedDateString);
}
Request conditionalRequest = conditionalRequestBuilder.build();
return hasConditions(conditionalRequest)
? new CacheStrategy(conditionalRequest, cacheResponse) //如果缓存数据被修改,则采用该策略
: new CacheStrategy(conditionalRequest, null); //否则摒弃缓存响应
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
2、下半部分,连接服务器
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean success = false;
try {
//Socket连接
httpStream = connect();
httpStream.setHttpEngine(this);
//------代码省略--------
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
我们看下connect()这个方法实现,它的最终实现是调用了StreamAllocation类中的newStream()方法
public HttpStream newStream(int connectTimeout, int readTimeout, int writeTimeout,
boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
throws RouteException, IOException {
try {
//连接服务器
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
//-----代码省略-------
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
findHealthyConnection(connectTimeout, readTimeout,writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks)方法的实现,他最终调用的是
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
boolean connectionRetryEnabled) throws IOException, RouteException {
Route selectedRoute;
synchronized (connectionPool) {
if (released) throw new IllegalStateException("released");
if (stream != null) throw new IllegalStateException("stream != null");
if (canceled) throw new IOException("Canceled");
RealConnection allocatedConnection = this.connection;
if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
return allocatedConnection;
}
// 尝试从连接池中找到与该连接地址相同的请求,并返回该连接.
RealConnection pooledConnection = Internal.instance.get(connectionPool, address, this);
if (pooledConnection != null) {
this.connection = pooledConnection;
return pooledConnection;
}
selectedRoute = route;
}
if (selectedRoute == null) {
selectedRoute = routeSelector.next();
synchronized (connectionPool) {
route = selectedRoute;
refusedStreamCount = 0;
}
}
//新的路线,建立连接
RealConnection newConnection = new RealConnection(selectedRoute);
acquire(newConnection);
//将新建立的连接添加到连接池中
synchronized (connectionPool) {
Internal.instance.put(connectionPool, newConnection);
this.connection = newConnection;
if (canceled) throw new IOException("Canceled");
}
//开始连接
newConnection.connect(connectTimeout, readTimeout, writeTimeout, address.connectionSpecs(),
connectionRetryEnabled);
routeDatabase().connected(newConnection.route());
return newConnection;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
.connect(connectTimeout, readTimeout, writeTimeout, address.connectionSpecs(),connectionRetryEnabled)方法实现,最终调用的是
public void connect(int connectTimeout, int readTimeout, int writeTimeout,
List<ConnectionSpec> connectionSpecs, boolean connectionRetryEnabled) throws RouteException {
//------代码省略------
while (protocol == null) { //假如协议protocol为null
try {
if (route.requiresTunnel()) { //假如sslSocket不为空并且代理类型为HTTP,则为true
buildTunneledConnection(connectTimeout, readTimeout, writeTimeout,
connectionSpecSelector); //创建连接通道,包括socket连接,SSL、TLS协议证书等连接
} else {
buildConnection(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);
}
} catch (IOException e) {
//-----代码省略-------
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
我们再看下buildTunneledConnection(connectTimeout, readTimeout, writeTimeout,connectionSpecSelector)这个方法
/**
* Does all the work to build an HTTPS connection over a proxy tunnel. The catch here is that a
* proxy server can issue an auth challenge and then close the connection.
*/
private void buildTunneledConnection(int connectTimeout, int readTimeout, int writeTimeout,
ConnectionSpecSelector connectionSpecSelector) throws IOException {
Request tunnelRequest = createTunnelRequest();//创建一个通道请求
HttpUrl url = tunnelRequest.url();
int attemptedConnections = 0;
int maxAttempts = 21; //最大的连接尝试次数
while (true) {
if (++attemptedConnections > maxAttempts) {
throw new ProtocolException("Too many tunnel connections attempted: " + maxAttempts);
}
//连接socket
connectSocket(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);
tunnelRequest = createTunnel(readTimeout, writeTimeout, tunnelRequest, url);
if (tunnelRequest == null) break; // Tunnel successfully created.
// The proxy decided to close the connection after an auth challenge. We need to create a new
// connection, but this time with the auth credentials.
Util.closeQuietly(rawSocket);
rawSocket = null;
sink = null;
source = null;
}
//建立连接,包括握手等功能
establishProtocol(readTimeout, writeTimeout, connectionSpecSelector);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
我们再看下establishProtocol(readTimeout, writeTimeout, connectionSpecSelector);这个方法的实现
private void establishProtocol(int readTimeout, int writeTimeout,
ConnectionSpecSelector connectionSpecSelector) throws IOException {
if (route.address().sslSocketFactory() != null) {
//与服务器进行握手连接
connectTls(readTimeout, writeTimeout, connectionSpecSelector);
} else {
protocol = Protocol.HTTP_1_1;
socket = rawSocket;
}
//如果网络请求的协议是spdy/3.1 或者h2 时,则执行如下方法
if (protocol == Protocol.SPDY_3 || protocol == Protocol.HTTP_2) {
socket.setSoTimeout(0); // Framed connection timeouts are set per-stream.
FramedConnection framedConnection = new FramedConnection.Builder(true)
.socket(socket, route.address().url().host(), source, sink)
.protocol(protocol)
.listener(this)
.build();
framedConnection.start();
// Only assign the framed connection once the preface has been sent successfully.
this.allocationLimit = framedConnection.maxConcurrentStreams();
this.framedConnection = framedConnection;
} else {
this.allocationLimit = 1;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
小结:至此,HttpEngine的发送请求方法的流程到这里已经走完,下面讲解engine.readResponse()方法
3.3.2 engine.readResponse() 读取响应数据
改方法的实现如下;
/**
* Flushes the remaining request header and body, parses the HTTP response headers and starts
* reading the HTTP response body if it exists.
*/
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) { //callerWritesRequestBody此值为fale
networkResponse = new NetworkInterceptorChain(0, networkRequest,
streamAllocation.connection()).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.
//如果缓存不为空,并且缓存数据有更新,则将新数据与之前的缓存数据通过调用responseCache.update方法进行更新操作,并将数据进行压缩输出(gzip)
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, 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));
}
}