连接(Connections)¶
虽然你只提供URL,但OkHttp按计划会使用三种类型连接到你的Web服务器:URL、Address和Route。
URLs¶
URLs (如 https:// github.com/square/okhttp
) 是HTTP和互联网的基础。 除了成为万维网上所有东西的通用、分散的命名方案外,它们还规定了如何访问万维网资源。
URLs是抽象的:
- 它们指定调用可以是明文(
http
),也可以是加密的(https
),但不指定应该使用哪种加密算法。 他们也没有指定如何验证对方的证书 (HostnameVerifier) 或哪些证书可以被信任 (SSLSocketFactory)。 - 它们不指定是否应该使用特定的代理服务器或如何向该代理服务器进行身份验证。
它们也是具体的: 每个URL标识一个特定的path (如 /square/okhttp
) 和query (如 ?q=sharks&lang=en
)。 每个Web服务器托管许多URL。
Addresses¶
Address指定一个web服务器 (如 github.com
) 和连接到该服务器所需的所有 静态 配置: 端口号、HTTPS设置和首选网络协议(如HTTP/2)。
共享相同地址的url也可能共享相同的底层TCP套接字连接。 共享连接有很大的性能优势:更低的延迟、更高的吞吐量(由于Tcp Slow start)和省电)。 OkHttp使用一个 ConnectionPool,它自动重用HTTP/1.X连接并多路复用HTTP/2连接。
在OkHttp中,Address的一些字段来自URL(scheme、主机名、端口),其余的来自OkHttpClient.
Routes¶
Routes提供实际连接到web服务器所需的 动态 信息。 这包含要尝试的特定IP地址(由dns查询发现)、要使用的确切代理服务器(如果正在使用ProxySelector)以及要协商的tls版本(对于HTTPS连接)。
一个地址可能有很多路线。 例如,托管在多个数据中心的Web服务器可能会在其DNS响应中产生多个IP地址。
在受限的情况下,如果连接失败,OkHttp将重试路由:
- 通过HTTP代理建立HTTPS连接时,代理可能会发出身份验证质询。 OkHttp将调用代理 authenticator,然后重试。
- 使用多个[Connection specs](https://square.github.io/okhttp/4.x/okhttp/okhttp3/-connection-spec/]建立TLS连接时,会按顺序尝试这些连接,直到TLS握手成功。
Connections¶
当你使用OkHttp请求URL时,以下是它的工作过程:
- 它使用URL并配置OkHttpClient来创建**address**。 此地址指定我们将如何连接到Web服务器。
- 它尝试从 **连接池 ** 中检索与该地址的连接。
- 如果它在池中没有找到连接,它会选择一个**route**进行尝试。 这通常意味着发出DNS请求以获取服务器的ip地址。 然后,如果需要,它会选择TLS版本和代理服务器。
- 如果是新route,则通过建立直接套接字连接,TLS隧道 (用于通过HTTP代理的HTTPS) 或直接TLS连接来连接。 它会在必要时进行TLS握手。 对于隧道挑战和TLS握手失败,可以重试此步骤。
- 它发送HTTP请求并读取响应。
如果连接有问题,OkHttp将选择另一条route,然后重试。 这允许OkHttp在服务器地址的子集无法访问时进行恢复。 当池连接超时或不支持尝试的TLS版本时,这也很有用。
收到响应后,连接将返回到池中,以便可以在将来的请求中重复使用。 一段时间不活动后,连接被逐出池。
Fast Fallback¶
从5.0版本开始,OkHttpClient
支持快速Fallback,这是我们实现的Happy Eyeballsrfc 6555.
通过快速Fallback,OkHttp尝试同时连接到多个web服务器。 它保留最先连接的那条路线,并取消所有其他路线。 它的规则是:
- 优先从不同地址族(IPv6/IPv4)中替换IP地址,从IPv6开始。
- 直到最近一次尝试开始后250毫秒,才开始新尝试。
- 保留最先成功的TCP连接,取消所有其他连接。
- 仅限TCP竞争。仅尝试在获胜的TCP连接上进行TLS握手。
如果TCP握手竞争的获胜者在TLS握手中失败,则使用剩余的路由重新启动该过程。