深入剖析OkHttp系列(一) 来自官方的OkHttp设计思想(中英互译)

1,435 阅读9分钟

本文译自OkHttp官方Wiki文档

The HTTP client’s job is to accept your request and produce its response. This is simple in theory but it gets tricky in practice.

Calls

该HttpClient的作用是接收你的请求并生成响应。 这在理论上来说是很简单的, 但是在实践上, 却很棘手。

Requests

Each HTTP request contains a URL, a method (like GET or POST), and a list of headers. Requests may also contain a body: a data stream of a specific content type.

每个Http请求都包含一个URL, 一个方法(如GET或POST), 还有一系列的header。 Request中可能会包含一个Body: 一个特定类型的数据流。

Responses

The response answers the request with a code (like 200 for success or 404 for not found), headers, and its own optional body.

Response会以一个返回码(像请求成功的200 或 找不到请求的404), 一系列的请求头,以及它自身的body来响应你的请求。

Rewriting Requests

When you provide OkHttp with an HTTP request, you’re describing the request at a high-level: “fetch me this URL with these headers.” For correctness and efficiency, OkHttp rewrites your request before transmitting it.

当你通过OkHttp发起一个Http请求时, 其实你是在一个high-level上描述一个请求: “通过这些请求头访问这个URL”。 为了确保准确性和高效性, Okhttp会再请求传输之前, 重写你的请求。

OkHttp may add headers that are absent from the original request, including Content-Length, Transfer-Encoding, User-Agent, Host, Connection, and Content-Type. It will add an Accept-Encoding header for transparent response compression unless the header is already present. If you’ve got cookies, OkHttp will add a Cookie header with them.

OkHttp可能会再原始请求中添加缺少的请求头, 包含Content-Length, Transfer-Encoding, User-Agent, Host, Connection, 和 Content-Type。 OkHttp将会为透明压缩响应添加一个Accept-Encoding请求头, 除非该请求头已经有了。如果你要获取cookies, OkHttp会添加一个Cookie请求头。

Some requests will have a cached response. When this cached response isn’t fresh, OkHttp can do a conditional GET to download an updated response if it’s newer than what’s cached. This requires headers like If-Modified-Since and If-None-Match to be added.

有些请求将会缓存响应。当这个缓存响应不是最新时, OkHttp会额外的执行一次Get请求去下载更新的响应, 如果这个响应比缓存的更新的话。这就需要像 If-Modified-Since and If-None-Match这样的请求头的添加。

Rewriting Responses

If transparent compression was used, OkHttp will drop the corresponding response headers Content-Encoding and Content-Length because they don’t apply to the decompressed response body.

如果要使用透明压缩, OkHttp将会删除相应的响应头Content-Encoding 和 Content-Length, 因为这些请求头是不适用于压缩响应体的。

If a conditional GET was successful, responses from the network and cache are merged as directed by the spec.

如果一个Get请求成功了, 网络和缓存的响应会直接按规范合并。

Follow-up Requests

When your requested URL has moved, the webserver will return a response code like 302 to indicate the document’s new URL. OkHttp will follow the redirect to retrieve a final response.

当你的请求URL被移动了, 服务器将会返回一个code, 如302,来指向文档的新URL。 OkHttp会遵循重定向来修正最终的响应。

If the response issues an authorization challenge, OkHttp will ask the Authenticator (if one is configured) to satisfy the challenge. If the authenticator supplies a credential, the request is retried with that credential included.

如果响应发出授权申请,OkHttp将会询问验证器(如果配置了的话)来响应申请。如果验证器提供了一个凭证, 这次请求会带着凭证重新请求。

Retrying Requests

Sometimes connections fail: either a pooled connection was stale and disconnected, or the webserver itself couldn’t be reached. OkHttp will retry the request with a different route if one is available.

有时连接失败: 池连接失效并断开连接, 或 服务器本身无法被访问。 OkHttp会通过不同的有效路由重试请求。

Calls

With rewrites, redirects, follow-ups and retries, your simple request may yield many requests and responses. OkHttp uses Call to model the task of satisfying your request through however many intermediate requests and responses are necessary. Typically this isn’t many! But it’s comforting to know that your code will continue to work if your URLs are redirected or if you failover to an alternate IP address.

通过重写,重定向,后续追踪和重试, 你的简单的请求可能会产生很多请求和响应。OkHttp使用Call来模拟满足你请求的任务, 然而很多中间的请求和响应是必需的。通常这种情况不是很多!但是, 如果你的URL被重定向, 或者故障被转移到备用的IP地址,你的代码将依然有效的执行,这一点很棒!

Calls are executed in one of two ways:

Synchronous: your thread blocks until the response is readable. Asynchronous: you enqueue the request on any thread, and get called back on another thread when the response is readable.

Calls can be canceled from any thread. This will fail the call if it hasn’t yet completed! Code that is writing the request body or reading the response body will suffer an IOException when its call is canceled.

Calls可以被以下两种方式之一执行:
同步: 你的线程会阻塞, 知道响应返回。
异步: 你可以将请求加入任何线程, 并在响应返回时, 在其他线程回调

Calls可以任意线程被取消。 这将会在请求还没有完成时,使其失败。 在Call被取消后,正在写请求体或读响应体的代码将会抛出IO异常。

Dispatch

For synchronous calls, you bring your own thread and are responsible for managing how many simultaneous requests you make. Too many simultaneous connections wastes resources; too few harms latency.

For asynchronous calls, Dispatcher implements policy for maximum simultaneous requests. You can set maximums per-webserver (default is 5), and overall (default is 64).

对于同步请求, 你可以自己创建线程并负责管理同时发出的请求数。 同时发出太多请求会浪费资源, 太少会存在延迟的弊端。 对于异步请求, Dispatcher实现了最大同时请求的策略。 你可以设置每个服务器的最大连接数(默认是5), 和总连接数(默认是64)。


Connections

Although you provide only the URL, OkHttp plans its connection to your webserver using three types: URL, Address, and Route.

尽管你只提供URL, OkHttp使用三种形式连接服务器:URL, 地址 和 路由。

URLS

URLs (like github.com/square/okht…) are fundamental to HTTP and the Internet. In addition to being a universal, decentralized naming scheme for everything on the web, they also specify how to access web resources.

URL是Http和网络的基础。除了用来在Web上作为一个统一的, 分散的命名方案外,它们还指明了如何来访问网络资源。

URLs are abstract:

They specify that the call may be plaintext (http) or encrypted (https), but not which cryptographic algorithms should be used. Nor do they specify how to verify the peer's certificates (the HostnameVerifier) or which certificates can be trusted (the SSLSocketFactory). They don't specify whether a specific proxy server should be used or how to authenticate with that proxy server.

URL是抽象的:
它们指明了call可以是明文或密文, 但是没有指明应该使用哪些加密算法。
它们没指明怎么去验证对方的证书, 或哪些证书可以被信任。
它们没有指明一个指定的代理服务是否可以被使用,或如何使用代理服务进行身份验证。

They're also concrete: each URL identifies a specific path (like /square/okhttp) and query (like ?q=sharks&lang=en). Each webserver hosts many URLs.

URL也是具体的:
每个URL指定了一个特定的路径(如like/square/okhttp)和查询(如?q=sharks&lang=en)。每个服务器持有很多URLS。

Addresses

Addresses specify a webserver (like github.com) and all of the static configuration necessary to connect to that server: the port number, HTTPS settings, and preferred network protocols (like HTTP/2 or SPDY).

Addresses指定了一个Web服务器和连接到这个服务器所需的所有静态配置: 端口号, HTTPS设置和相关的网络协议(如HTTP/2 或 SPDY)。

URLs that share the same address may also share the same underlying TCP socket connection. Sharing a connection has substantial performance benefits: lower latency, higher throughput (due to TCP slow start) and conserved battery. OkHttp uses a ConnectionPool that automatically reuses HTTP/1.x connections and multiplexes HTTP/2 and SPDY connections.

共享相同地址的URLs可能也会共享相同的底层TCP套接字连接。 共享连接具有显著的性能优势:
更低的延迟
更高的吞吐量(由于TCP的慢启动)
节省电源
OkHttp使用连接池, 自动重用 HTTP/1.x连接 并多路复用HTTP/2和SPDY连接。

In OkHttp some fields of the address come from the URL (scheme, hostname, port) and the rest come from the OkHttpClient.

在OkHttp中, Address的某些字段来自于URL(方案, 主机名, 端口) , 其余字段来自OkHttpClient。

Routes

Routes supply the dynamic information necessary to actually connect to a webserver. This is the specific IP address to attempt (as discovered by a DNS query), the exact proxy server to use (if a ProxySelector is in use), and which version of TLS to negotiate (for HTTPS connections).

路由提供了实际连接到Web服务器所需的动态信息。这是要尝试的特定IP地址(由DNS查询发现), 要使用的确切的代理服务器(如果使用了ProxySelector), 以及要协定的TLS版本(对于HTTPS连接而言)。

There may be many routes for a single address. For example, a webserver that is hosted in multiple datacenters may yield multiple IP addresses in its DNS response.

单个地址可能会有很多路由。 比如, 一个托管在多个数据中心的Web服务器, 可能会在DNS响应中产生多个IP地址。

Connections

When you request a URL with OkHttp, here's what it does:

It uses the URL and configured OkHttpClient to create an address. This address specifies how we'll connect to the webserver. It attempts to retrieve a connection with that address from the connection pool. If it doesn't find a connection in the pool, it selects a route to attempt. This usually means making a DNS request to get the server's IP addresses. It then selects a TLS version and proxy server if necessary. If it's a new route, it connects by building either a direct socket connection, a TLS tunnel (for HTTPS over an HTTP proxy), or a direct TLS connection. It does TLS handshakes as necessary. It sends the HTTP request and reads the response. If there's a problem with the connection, OkHttp will select another route and try again. This allows OkHttp to recover when a subset of a server's addresses are unreachable. It's also useful when a pooled connection is stale or if the attempted TLS version is unsupported.

当你使用OkHttp访问一个URL时, 它做了什么:
它使用URL和配置的OkHttpClient创建一个地址。 该地址指明了我们如何连接Web服务器。它尝试通过这个地址从连接池中恢复这个连接。如果再连接池中没有找到连接,它会选择一个路由去尝试。这通常意味着发出一个DNS请求来获取服务端的IP地址。 然后如果需要, 它会选择一个TLS版本和代理服务。如果它是一个新的路由, 它会通过直接构建一个新的socket连接, 一个TLS通道(对于HTTP代理的HTTPS), 或者一个直接的TLS连接, 并根据需要进行TLS握手。

它发送一个HTTP请求并读取响应。

如果连接有问题, OkHttp会选择其他路由并重新尝试。这使得OkHttp当在一个服务器的地址的子集无法访问时,进行恢复。当池化连接失效, 或尝试的TLS版本不支持时, 也是有用的。

Once the response has been received, the connection will be returned to the pool so it can be reused for a future request. Connections are evicted from the pool after a period of inactivity.

一旦响应到达, 连接会返回到连接池中, 这样在以后的请求中就可以复用了。 一段时间不活跃后, 连接会从连接池中被移除。