还有个问题就是为什么有当前连接??明明还没开始连接也没有获取连接啊,怎么连接就被赋值了?
还记得 重试和重定向 拦截器吗?对了,就是当请求失败需要重试的时候或者重定向的时候,这时候连接还在呢,是可以直接进行复用的 。
- 2和3、从连接池中获取可用连接
connectionPool.callAcquirePooledConnection(address, call, null, false)connectionPool.callAcquirePooledConnection(address, call, routes, false)好像多了一个 routes 字段?这里涉及到HTTP/2的一个技术,叫做 HTTP/2 CONNECTION COALESCING (连接合并),什么意思呢?
假设有两个域名,可以解析为相同的IP地址,并且是可以用相同的TLS证书(比如通配符证书),那么客户端可以重用相同的 TCP连接 从这两个域名中获取资源 。
再看回我们的连接池,这个 routes 就是当前域名(主机名)可以被解析的 ip地址 集合,这两个方法的区别也就是一个传了路由地址,一个没有传 。
继续看
callAcquirePooledConnection 代码:
internal fun isEligible(address: Address, routes: List<Route>?): Boolean {if (address.url.host == this.route().address.url.host) {return true}//HTTP/2 CONNECTION COALESCINGif (http2Connection == null) return falseif (routes == null || !routeMatchesAny(routes)) return falseif (address.hostnameVerifier !== OkHostnameVerifier) return falsereturn true}1)判断主机名、端口号等,如果请求完全相同就直接返回这个连接 。2)如果主机名不同,还可以判断是不是 HTTP/2 请求,如果是就继续判断路由地址,证书,如果都能匹配上,那么这个连接也是可用的 。
- 4、创建新连接
- 5、再从连接池获取一次连接,防止在新建连接过程中有其他竞争连接被创建了
因为在这个过程中,有可能有其他的请求和你一起创建了新连接,所以我们需要再去取一次连接,如果有可以用的,就直接用它,防止资源浪费 。
其实这里又涉及到HTTP2的一个知识点: 多路复用 。
简单的说,就是不需要当前连接的上一个请求结束之后再去进行下一次请求,只要有连接就可以直接用 。
HTTP/2引入二进制数据帧和流的概念,其中帧对数据进行顺序标识,这样在收到数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况 。同样是因为有了序列,服务器就可以并行的传输数据,这就是流所做的事情 。
所以在 HTTP/2 中可以保证在同一个域名只建立一路连接,并且可以并发进行请求 。
- 6、新连接放入连接池,并返回
这个拦截器确实麻烦,大家好好梳理下吧,我也再来个图:

文章插图
IO拦截器(CallServerInterceptor)连接拿到了,编码解码器有了,剩下的就是发数据,读数据了,也就是跟 I/O 相关的工作 。
class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor {@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {//写header数据exchange.writeRequestHeaders(request)//写body数据if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()requestBody.writeTo(bufferedRequestBody)} else {exchange.noRequestBody()}//结束请求if (requestBody == null || !requestBody.isDuplex()) {exchange.finishRequest()}//获取响应数据var response = responseBuilder.request(request).handshake(exchange.connection.handshake()).build()var code = response.coderesponse = response.newBuilder().body(exchange.openResponseBody(response)).build()return response}}这个拦截器 倒是没干什么活,之前的拦截器兄弟们都把准备工作干完了,它就调用下 exchange 类的各种方法,写入 header,body ,拿到 code,response 。这活可干的真轻松啊 。
被遗漏的自定义拦截器(networkInterceptors)好了,最后补上这个拦截器 networkInterceptors ,它也是一个自定义拦截器,位于 CallServerInterceptor 之前,属于倒数第二个拦截器 。
推荐阅读
- 从零开始怎样练太极拳基本功
- 调养视网膜脱落从太极拳养身开始
- 招聘|从一线到三四线城市,中超赛区接连遇冷,陈戌源担心事情还是发生
- 五亿年后的地球 从宇宙诞生到地球灭亡
- nasa空间站直播 nasa国际空间站直播
- 路由器|坐等换路由!Wi-Fi 7加速到来:网络体验完美取代Wi-Fi 6
- 十大潮州美食推荐
- 紫沙茶罐图片,图片来源于网络
- K8S 的网络架构弄清楚了吗?
- 爱因斯坦说蜜蜂在地球上消失 爱因斯坦说蜜蜂如果从世界上消失会怎么样
