okhttp详解系列五:连接拦截器 ConnectInterceptor

连接拦截器(ConnectInterceptor)负责与服务器建立网络连接,连接缓存池、dns解析、https证书校验等都在连接拦截器阶段来执行。连接拦截器类中的代码非常少,主要逻辑都在Exchange的初始化中:

1
2
3
4
5
6
7
8
9
10
11
12
13
object ConnectInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
// 1. 初始化Exchange
val exchange = realChain.call.initExchange(chain)
val connectedChain = realChain.copy(exchange = exchange)
// 2. 交给下一个拦截器进行处理,如果用户注册了网络拦截器,
// 下一个拦截器就是用户注册的网络拦截器
val result = connectedChain.proceed(realChain.request)
return result
}
}

连接拦截器的主要时序:


zenuml
ConnectInterceptor.intercept {
    RealCall.initExchange {
        ExchangeCodec = ExchangeFinder.find {
            RealConnection = findHealthyConnection {
                findConnection
            }
            ExchangeCodec = RealConnection.newCodec {
                if (http2) {
                    "new Http2ExchangeCodec()"
                } else {
                    "new Http1ExchangeCodec()"
                }
            }
        }
        new Exchange
    }
    RealInterceptorChain."copy(传入Exchange)"
    RealInterceptorChain."proceed(把网络请求交给下一个拦截器)"
}

连接池查找可用连接

下面流程图是从okhttp3.internal.connection.ExchangeFinder#findConnection开始进行分析:

新的请求与connection是否是相同的host和port不同相同删除该connection与call之间的关联将connection标记被idle状态关闭socket为空connection关联的calls列表为空复用当前connection不为空当前connection是否为空?(RealCall持有的RealConnection)查找连接池连接池中存在可用连接存在不存在关联call与connection返回连接池中找的的连接创建路由解析器并解析ip地址基于IP地址再次查找连接池返回可用连接yes存在可用连接不使用使用合并连接的路由,或者使用已存在路由选择器的路由创建新的Connection连接服务器查找连接池是否存在多路复用的connection(HTTP/2)存在不存在关闭新建connection的socket返回多路复用的connection新连接放到连接池中关联call与connection返回新建连接

连接拦截器类图结构

ConnectInterceptorRealInterceptorChainExchangeExchangeFinderExchangeCodecRealCallOkHttpClientRealConnectionHttp1ExchangeCodecHttp2ExchangeCodecSocketRealConnectionPoolAddressDnsDnsSystem10..nrawSocketsocket0..n1

备注

https证书校验在okhttp3.internal.tls.OkHostnameVerifier#verify(java.lang.String, javax.net.ssl.SSLSession)