本文中源码基于OkHttp 3.6.0
- 《OkHttp Request 请求执行流程》
- 《OkHttp - Interceptors(一)》
- 《OkHttp - Interceptors(二)》
- 《OkHttp - Interceptors(三)》
- 《OkHttp - Interceptors(四)》
这篇文章主要分析 ConnectInterceptor ,它是 OkHttp 请求链上的倒数第二个节点,其主要任务就是创建与服务器的连接。
- ConnectInterceptor
先来看其 intercept 方法。
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
这里的代码比较少,创建了一个 HTTP 编解码器HttpCodec
和一个连接对象RealConnection
,并将它们加入到请求链中,其中HttpCodec
主要用于在CallServerInterceptor
中向服务器发起 Request 和解析 Response。构建这两个对象的主要逻辑全部封装在StreamAllocation
中,它在请求链的第一个节点RetryAndFollowupInterceptor
中创建的。
来看其 newStream() 方法。
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
throws IOException {
while (true) {
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
connectionRetryEnabled);
// 如果 connection 是一个新创建的,那么不用进行健康性测试
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
// 健康检查主要是判断 socket 是否关闭,输入输出流是否关闭等。
// 如果连接不健康,则断开连接,并从 connectionPool 中移除。
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
noNewStreams();
continue;
}
return candidate;
}
}
通过 findHealthyConnection() 找到一条可用的连接。
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
throws IOException {
while (true) {
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
connectionRetryEnabled);
// 如果 connection 是一个新创建的,那么不用进行健康性测试
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
// 健康检查主要是判断 socket 是否关闭,输入输出流是否关闭等。
// 如果连接不健康,则断开连接,并从 connectionPool 中移除。
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
noNewStreams();
continue;
}
return candidate;
}
}
继续进入 findConnection()。
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
boolean connectionRetryEnabled) throws IOException {
Route selectedRoute;
synchronized (connectionPool) {
if (released) throw new IllegalStateException("released");
if (codec != null) throw new IllegalStateException("codec != null");
if (canceled) throw new IOException("Canceled");
// StreamAllocation 会保持了一个当前的连接,如果这个连接允许继续使用,则直接复用这个连接
RealConnection allocatedConnection = this.connection;
if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
return allocatedConnection;
}
// 从连接池中找到一个可以复用的连接
Internal.instance.get(connectionPool, address, this);
if (connection != null) {
return connection;
}
selectedRoute = route;
}
// 如果没有合适的连接,那么就创建一个新的
// 寻找一个合适的路由,如果没有找到就抛出异常,由 RetryAndFollowUpInterceptor 负责捕获并重试
if (selectedRoute == null) {
selectedRoute = routeSelector.next();
}
RealConnection result;
synchronized (connectionPool) {
route = selectedRoute;
refusedStreamCount = 0;
result = new RealConnection(connectionPool, selectedRoute);
acquire(result);
if (canceled) throw new IOException("Canceled");
}
// 执行三次握手,创建与服务器的连接
result.connect(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled);
routeDatabase().connected(result.route());
Socket socket = null;
synchronized (connectionPool) {
// 把这个连接放进连接池,供以后复用
Internal.instance.put(connectionPool, result);
if (result.isMultiplexed()) {
socket = Internal.instance.deduplicate(connectionPool, address, this);
result = connection;
}
}
closeQuietly(socket);
return result;
}
在执行 connect() 的时候,使用 Socket 建立连接,如果请求是 HTTPS,则使用 SSLSocket 进行包装。
那么,至此客户端与服务器之间的连接就已经建立成功了,如果 OkHttpClient 中设置了 networkInterceptor 的话,下面就该把任务交给它们处理了,这里就可以看出 networkInterceptor 和 Interceptor 之间的区别,networkInterceptor 处理请求时已经建立好连接。如果没有设置 networkInterceptor,下面就该 CallServerInterceptor 出场了。
网友评论