深入剖析OkHttp系列(一) 來自官方的OkHttp設計思想(中英互譯)

亓春傑發表於2018-08-15

本文譯自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.

一旦響應到達, 連線會返回到連線池中, 這樣在以後的請求中就可以複用了。 一段時間不活躍後, 連線會從連線池中被移除。

相關文章