多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > OkHttp 官方中文文檔

OkHttp 官方中文文檔

來源:程序員人生   發(fā)布時(shí)間:2016-07-13 10:18:30 閱讀次數(shù):3390次

OkHttp官方中文文檔

本文結(jié)構(gòu)

  • Calls
  • Connections
  • Recipes
  • Interceptors
  • HTTPS
    本文翻譯來自 官方OkHttp Wiki

  • OkHttp官方中文文檔
    • 1Calls
      • 1 要求
      • 2 響應(yīng)
      • 3重寫要求
      • 4重寫響應(yīng)
      • 5后續(xù)要求
      • 6要求重試
      • 7 呼喚
      • 8調(diào)度
    • 2Connections
      • 1URLs
          • URLs摘要
      • 2 Addresses
      • 3 Routes
      • 4Connections
    • 3Recipes
      • 1同步獲得
      • 2異步獲得
      • 3訪問頭
      • 4Posting a String
      • 5 Post Streaming
      • 6 Posting a File
      • 7 發(fā)布表單參數(shù)
      • 8 發(fā)布multipart要求
      • 9 通過GSON解析響應(yīng)的JSON
      • 10 響應(yīng)緩存
      • 11 取消Call
      • 12 超時(shí)
      • 13 每一個(gè)呼喚配置
      • 14 認(rèn)證處理
    • 4攔截器
      • 1 利用攔截器
      • 2 網(wǎng)絡(luò)攔截器
      • 3 利用程序和網(wǎng)絡(luò)攔截之間進(jìn)行選擇
        • 利用攔截器
        • 網(wǎng)絡(luò)攔截器
      • 4重寫要求
      • 5 重寫響應(yīng)
      • 6 可用性
    • 5 HTTPS
      • 1證書釘扎
      • 2定制信任證書

1、Calls

HTTP客戶真?zhèn)€工作是接受你的request,并產(chǎn)生它的response。這個(gè)在理論上是簡(jiǎn)單的,但在實(shí)踐中確是很辣手。

1.1 要求

每個(gè)HTTP要求中都包括1個(gè)URL,1個(gè)方法(如GETPOST),和1個(gè)要求頭列表(headers)。要求還可以含有1個(gè)要求體(body):1個(gè)特定內(nèi)容類型的數(shù)據(jù)流。

1.2 響應(yīng)

每個(gè)HTTP響應(yīng)中都包括1個(gè)狀態(tài)碼(如200代表成功,404代表未找??到),1個(gè)響應(yīng)頭列表(headers)和1個(gè)可選的響應(yīng)體(body)。

1.3重寫要求

當(dāng)你的OkHttp發(fā)送1個(gè)HTTP要求,你在描寫1個(gè)高層次的要求:“給我獲得這個(gè)網(wǎng)址中的這些要求頭。”對(duì)正確性和效力,OkHttp發(fā)送前會(huì)重寫你的要求。

OkHttp可以從原來的要求中添加要求頭(headers),包括Content-Length, Transfer-Encoding, User-Agent, Host, Connection, 和 Content-Type。除非要求頭已存在緊縮響應(yīng),否則它還將添加1個(gè)Accept-Encoding要求頭。如果你有cookies,OkHttp還將添加1個(gè)Cookie要求頭。

1些要求會(huì)有1個(gè)緩存的響應(yīng)。當(dāng)這個(gè)緩存的響應(yīng)不是最新的,OkHttp會(huì)發(fā)送1個(gè)有條件的GET來下載更新的響應(yīng),如果它比緩存還新。它將會(huì)添加需要的要求頭,如IF-Modified-SinceIf-None-Match

1.4重寫響應(yīng)

如果使用的是透明緊縮,OkHttp會(huì)丟失相應(yīng)的響應(yīng)頭Content-EncodingContent-Length,這是由于它們不能用于解壓響應(yīng)體(body)。

如果1個(gè)條件GET是成功的,在唆使的規(guī)范下響應(yīng)來自于網(wǎng)絡(luò)和緩存的合并。

1.5后續(xù)要求

當(dāng)你的要求的URL已移動(dòng),Web服務(wù)器將返回1個(gè)響應(yīng)碼像302,以表明本文檔的新的URL。OkHttp將依照重定向檢索的終究響應(yīng)。

如果響應(yīng)問題是1個(gè)的授權(quán)盤問,OkHttp將會(huì)要求身份驗(yàn)證(如果有1個(gè)已配置好),以滿足盤問。如果身份驗(yàn)證提供憑據(jù),要求將會(huì)帶著憑證進(jìn)行重試。

1.6要求重試

有時(shí)連接失敗:要末是連接池已過時(shí)和斷開,或是Web服務(wù)器本身沒法達(dá)成。如果有1個(gè)是可用的,OkHttp將會(huì)使用不同的路由進(jìn)行要求重試。

1.7 呼喚

隨側(cè)重寫,重定向,后續(xù)和重試,你簡(jiǎn)單的要求可能會(huì)產(chǎn)生很多要求和響應(yīng)。OkHttp使用呼喚(Call)并通過許多必要的中間要求和響應(yīng)來滿足你要求的任務(wù)模型。通常情況,這是否是很多!如果您的網(wǎng)址被重定向,或如果您故障轉(zhuǎn)移到另外一個(gè)IP地址,但它會(huì)欣慰的知道你的代碼會(huì)繼續(xù)工作。

通過以下兩種方式進(jìn)行呼喚:
- 同步:直到響應(yīng),你的線程塊是可讀的。
- 異步:你在任何線程進(jìn)行排隊(duì)要求,并且當(dāng)響應(yīng)是可讀的時(shí)候,你會(huì)在另外一個(gè)線程得到回調(diào)。

呼喚(Calls)可以在任何線程中取消。如果它還沒有完成,它將作為失敗的呼喚(Calls)!當(dāng)呼喚(Call)被取消的時(shí)候,如果代碼試圖進(jìn)行寫要求體(request body)或讀取響應(yīng)體(response body)會(huì)遭受IOException異常。

1.8調(diào)度

對(duì)同步調(diào)用,你帶上你自己的線程,并負(fù)責(zé)管理并發(fā)要求。并發(fā)連接過量浪費(fèi)資源; 過少的危害等待時(shí)間。

對(duì)異步調(diào)用,調(diào)度實(shí)現(xiàn)了最大同時(shí)要求策略。您可以設(shè)置每一個(gè)Web服務(wù)器最大值(默許值為5),和整體(默許為64)。

2、Connections

雖然只提供了URL,但是OkHttp計(jì)劃使用3種類型連接你的web服務(wù)器:URL, Address, 和 Route。

2.1URLs

URLs(如https://github.com/square/okhttp)是HTTP和因特網(wǎng)的基礎(chǔ)。除是網(wǎng)絡(luò)上通用的和分散的命名方案,他們還指定了如何訪問網(wǎng)絡(luò)資源。

URLs摘要:
  • 它們指定該呼喚(Call)可以被明文(HTTP)或加密的(HTTPS),但不指定用哪一個(gè)加密算法。他們也不指定如何驗(yàn)證對(duì)方的證書(HostnameVerifier)或證書可以信任(SSLSocketFactory)。
  • 他們不指定是不是應(yīng)使用特定的代理服務(wù)器或如何與該代理服務(wù)器進(jìn)行身份驗(yàn)證。

他們還具體:每一個(gè)URL辨認(rèn)特定的路徑(如 /square/okhttp)和查詢(如 ?q=sharks&lang=en)。每一個(gè)Web服務(wù)器主機(jī)的網(wǎng)址。

2.2 Addresses

Addresses指定網(wǎng)絡(luò)服務(wù)器(如github.com)和所有的靜態(tài)必要的配置,和連接到該服務(wù)器:端口號(hào),HTTPS設(shè)置和首選的網(wǎng)絡(luò)協(xié)議(如HTTP / 2SPDY)。

同享相同地址的URL也能夠同享相同的基礎(chǔ)TCP套接字連接。同享1個(gè)連接有實(shí)實(shí)在在的性能優(yōu)點(diǎn):更低的延遲,更高的吞吐量(由于TCP慢啟動(dòng))和保養(yǎng)電池。OkHttp使用的ConnectionPool自動(dòng)重用HTTP / 1.x的連接和多樣的HTTP/ 2和SPDY連接。

在OkHttp地址的某些字段來自URL(scheme, hostname, port),其余來自O(shè)kHttpClient。

2.3 Routes

Routes提供連接到1個(gè)網(wǎng)絡(luò)服務(wù)器所必須的動(dòng)態(tài)信息。就是嘗試特定的IP地址(如由DNS查詢發(fā)現(xiàn)),使用確切的代理服務(wù)器(如果1個(gè)特定的IP地址的ProxySelector在使用中)和協(xié)商的TLS版本(HTTPS連接)。

可能有單個(gè)地址對(duì)應(yīng)多個(gè)路由。例如,在多個(gè)數(shù)據(jù)中心托管的Web服務(wù)器,它可能會(huì)在其DNS響應(yīng)產(chǎn)生多個(gè)IP地址。

2.4Connections

當(dāng)你使用OkHttp進(jìn)行1個(gè)URL要求,下面是它的操作流程:

  1. 它使用URL和配置OkHttpClient創(chuàng)建1個(gè)address。此地址指定我們將如何連接到網(wǎng)絡(luò)服務(wù)器
  2. 它通過地址從連接池中取回1個(gè)連接。
  3. 如果它沒有在池中找到連接,它會(huì)選擇route嘗試。這通常意味著使1個(gè)DNS要求, 以獲得服務(wù)器的IP地址。如果需要,它會(huì)選擇1個(gè)的TLS版本和代理服務(wù)器
  4. 如果它是1個(gè)新的route,它連接通過建立不管是直接的socket連接,socket連接使用TLS安全通道(用于HTTPS通過1個(gè)HTTP代理),或直接TLS連接。它的TLS握手是必要的。
  5. 它發(fā)送HTTP要求并讀取響應(yīng)。
    如果有連接出現(xiàn)問題,OkHttp將選擇另外一條route,然后再試1次。當(dāng)1個(gè)服務(wù)器的地址的1個(gè)子集是不可達(dá)時(shí),這使得OkHttp能夠恢復(fù)。當(dāng)連接池是過時(shí)或試圖TLS版本不受支持時(shí),這類方式是很有用的。

1旦響應(yīng)已被接收到,該連接將被返回到池中,以便它可以在將來的要求中被重用。連接在池中閑置1段時(shí)間后,它會(huì)被趕出。

3、Recipes

我們已寫了1些方法,演示了如何解決OkHttp常見問題。通過瀏覽他們了解1切是如何正常工作的。可以自由剪切和粘貼這些例子。

3.1同步獲得

下載文件,打印其頭部,并以字符串情勢(shì)打印其響應(yīng)體。

string() 方法在響應(yīng)體中是方便快捷的小型文件。但是,如果響應(yīng)體是大的(大于1 MIB以上),它會(huì)在全部文件加載到內(nèi)存中,所以應(yīng)當(dāng)避免string() 。在這類情況下,更偏向于將響應(yīng)體作為流進(jìn)行處理。

private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); Headers responseHeaders = response.headers(); for (int i = 0; i < responseHeaders.size(); i++) { System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); } System.out.println(response.body().string()); }

3.2異步獲得

下載1個(gè)工作線程的文件,當(dāng)響應(yīng)是可讀的時(shí)候,獲得回調(diào)(Callback)。當(dāng)響應(yīng)頭已準(zhǔn)備好后,將產(chǎn)生回調(diào)(Callback)。讀取響應(yīng)體可能1直阻塞。目前OkHttp不提供異步API來接收響應(yīng)體的部位。

private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); Headers responseHeaders = response.headers(); for (int i = 0, size = responseHeaders.size(); i < size; i++) { System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); } System.out.println(response.body().string()); } }); }

3.3訪問頭

典型的HTTP頭工作就像1個(gè)Map<String, String> :每一個(gè)字段都有1個(gè)值或無值。但是,1些頭部(headers)允許多個(gè)值,比如Guava的Multimap。例如,它共同為1個(gè)HTTP響應(yīng)提供多個(gè)Vary頭。OkHttp的API,試圖使這兩種情況下都能舒適使用。

當(dāng)寫要求頭,用header(name, value)來為唯1出現(xiàn)的name設(shè)置value。如果存在現(xiàn)有值,在添加新的value之前,他們將被移除。使用addHeader(name, value)來添加頭部不需要移除當(dāng)前存在的headers

當(dāng)讀取響應(yīng)頭,用header(name)返回最后設(shè)置name的value。如果沒有valueheader(name)將返回null。讀取所有以列表字段的值,可使用headers(name)

要訪問所有的頭部,用Headers類,它支持索引訪問。

private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("https://api.github.com/repos/square/okhttp/issues") .header("User-Agent", "OkHttp Headers.java") .addHeader("Accept", "application/json; q=0.5") .addHeader("Accept", "application/vnd.github.v3+json") .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println("Server: " + response.header("Server")); System.out.println("Date: " + response.header("Date")); System.out.println("Vary: " + response.headers("Vary")); }

3.4Posting a String

使用HTTP POST的要求體發(fā)送到服務(wù)。下面例子post了1個(gè)markdown文檔到1個(gè)的Web服務(wù)(將markdown作為HTML)。由于全部要求體是同時(shí)在內(nèi)存中,應(yīng)避免使用此API發(fā)送較大(大于1 MIB)的文件。

public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf⑻"); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { String postBody = "" + "Releases\n" + "--------\n" + "\n" + " * _1.0_ May 6, 2013\n" + " * _1.1_ June 15, 2013\n" + " * _1.2_ August 11, 2013\n"; Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody)) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); }

3.5 Post Streaming

在這里,我們POST要求體作為stream。正在生成要求體的內(nèi)容寫入到stream中。下面例子streams直接進(jìn)入 Okio緩沖水槽。你的程序可能更喜歡使用OutputStream,你可以通過BufferedSink.outputStream()取得 OutputStream。

public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf⑻"); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { RequestBody requestBody = new RequestBody() { @Override public MediaType contentType() { return MEDIA_TYPE_MARKDOWN; } @Override public void writeTo(BufferedSink sink) throws IOException { sink.writeUtf8("Numbers\n"); sink.writeUtf8("-------\n"); for (int i = 2; i <= 997; i++) { sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i))); } } private String factor(int n) { for (int i = 2; i < n; i++) { int x = n / i; if (x * i == n) return factor(x) + " × " + i; } return Integer.toString(n); } }; Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(requestBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); }

3.6 Posting a File

它是很容易的將文件作為要求體。

public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf⑻"); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { File file = new File("README.md"); Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); }

3.7 發(fā)布表單參數(shù)

使用FormBody.Builder建立1個(gè)要求體,它就像1個(gè)HTML 的標(biāo)記。Namesvalues將使用HTML兼容的表單URL編碼進(jìn)行編碼。

private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { RequestBody formBody = new FormBody.Builder() .add("search", "Jurassic Park") .build(); Request request = new Request.Builder() .url("https://en.wikipedia.org/w/index.php") .post(formBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); }

3.8 發(fā)布multipart要求

MultipartBody.Builder可以構(gòu)建與HTML文件上傳表單兼容的復(fù)雜的要求主體。multipart要求體的每部份本身就是要求體,并且可以定義自己的頭部。如果存在,這些頭應(yīng)當(dāng)描寫的部份要求體,如它的Content-Disposition。如果Content-LengthContent-Type頭部可使用,則他們會(huì)自動(dòng)添加。

private static final String IMGUR_CLIENT_ID = "..."; private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png"); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("title", "Square Logo") .addFormDataPart("image", "logo-square.png", RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png"))) .build(); Request request = new Request.Builder() .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID) .url("https://api.imgur.com/3/image") .post(requestBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); }

3.9 通過GSON解析響應(yīng)的JSON

GSON是1個(gè)JSON和Java對(duì)象之間的便利轉(zhuǎn)換的API。這里,我們用它來解碼從GitHub的API 響應(yīng)的JSON。

需要注意的是ResponseBody.charStream()使用的Content-Type響應(yīng)頭進(jìn)行解碼時(shí),所使用的字符集,如果沒有指定字符集,它默許為UTF⑻ 。

private final OkHttpClient client = new OkHttpClient(); private final Gson gson = new Gson(); public void run() throws Exception { Request request = new Request.Builder() .url("https://api.github.com/gists/c2a7c39532239ff261be") .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); Gist gist = gson.fromJson(response.body().charStream(), Gist.class); for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) { System.out.println(entry.getKey()); System.out.println(entry.getValue().content); } } static class Gist { Map<String, GistFile> files; } static class GistFile { String content; }

3.10 響應(yīng)緩存

要緩存響應(yīng),你需要1個(gè)緩存目錄來進(jìn)行讀取和寫入,和1個(gè)緩存的大小限制。緩存目錄應(yīng)當(dāng)是私有的,不信任的利用程序不應(yīng)當(dāng)能夠?yàn)g覽其內(nèi)容!

多個(gè)緩存同時(shí)訪問相同的緩存目錄,這是毛病的。大多數(shù)利用程序應(yīng)當(dāng)調(diào)用1次new OkHttpClient(),用自己的緩存配置,在任何地方都使用相同的實(shí)例。否則,這兩個(gè)緩存實(shí)例將踩到對(duì)方,破壞響應(yīng)緩存,這可能使你的程序崩潰。

響應(yīng)緩存使用HTTP頭的所有配置。您可以添加要求頭Cache-Control: max-stale=3600和OkHttp的緩存會(huì)遵守他們。你的網(wǎng)絡(luò)服務(wù)器可以通過自己的響應(yīng)頭配置多長(zhǎng)時(shí)間緩存響應(yīng),如Cache-Control: max-age=9600。有緩存頭強(qiáng)迫緩存的響應(yīng),強(qiáng)迫網(wǎng)絡(luò)響應(yīng),或強(qiáng)迫使用條件GET驗(yàn)證的網(wǎng)絡(luò)響應(yīng)。

private final OkHttpClient client; public CacheResponse(File cacheDirectory) throws Exception { int cacheSize = 10 * 1024 * 1024; // 10 MiB Cache cache = new Cache(cacheDirectory, cacheSize); client = new OkHttpClient.Builder() .cache(cache) .build(); } public void run() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); Response response1 = client.newCall(request).execute(); if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1); String response1Body = response1.body().string(); System.out.println("Response 1 response: " + response1); System.out.println("Response 1 cache response: " + response1.cacheResponse()); System.out.println("Response 1 network response: " + response1.networkResponse()); Response response2 = client.newCall(request).execute(); if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2); String response2Body = response2.body().string(); System.out.println("Response 2 response: " + response2); System.out.println("Response 2 cache response: " + response2.cacheResponse()); System.out.println("Response 2 network response: " + response2.networkResponse()); System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body)); }

為了避免使用緩存的響應(yīng),使用CacheControl.FORCE_NETWORK。為了避免它使用網(wǎng)絡(luò),使用CacheControl.FORCE_CACHE。正告:如果您使用FORCE_CACHE和響應(yīng)要求網(wǎng)絡(luò),OkHttp將會(huì)返回1個(gè)504不可滿足要求的響應(yīng)。

3.11 取消Call

使用Call.cancel()立即停止正在進(jìn)行的Call。如果1個(gè)線程目前正在寫要求或讀響應(yīng),它還將收到1個(gè)IOException異常。當(dāng)1個(gè)Call不需要時(shí),使用此保護(hù)網(wǎng)絡(luò); 例如,當(dāng)用戶從利用程序?qū)Ш诫x開。同步和異步調(diào)用可以被取消。

private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. .build(); final long startNanos = System.nanoTime(); final Call call = client.newCall(request); // Schedule a job to cancel the call in 1 second. executor.schedule(new Runnable() { @Override public void run() { System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f); call.cancel(); System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f); } }, 1, TimeUnit.SECONDS); try { System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f); Response response = call.execute(); System.out.printf("%.2f Call was expected to fail, but completed: %s%n", (System.nanoTime() - startNanos) / 1e9f, response); } catch (IOException e) { System.out.printf("%.2f Call failed as expected: %s%n", (System.nanoTime() - startNanos) / 1e9f, e); } }

3.12 超時(shí)

當(dāng)其查詢沒法訪問時(shí),使用超時(shí)失敗的調(diào)用。網(wǎng)絡(luò)劃分可以是由于客戶端連接問題,服務(wù)器可用性的問題,或之間的任何東西。OkHttp支持連接,讀取和寫入超時(shí)。

private final OkHttpClient client; public ConfigureTimeouts() throws Exception { client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build(); } public void run() throws Exception { Request request = new Request.Builder() .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. .build(); Response response = client.newCall(request).execute(); System.out.println("Response completed: " + response); }

3.13 每一個(gè)呼喚配置

所有的HTTP客戶端配置都在OkHttpClient中包括代理設(shè)置,超時(shí)和緩存。當(dāng)你需要改變單1Call的配置時(shí),調(diào)用OkHttpClient.newBuilder() 。這將返回同享相同的連接池,調(diào)度和配置與原來的客戶真?zhèn)€建造器。在下面的例子中,我們做了500毫秒超時(shí),另外1個(gè)3000毫秒超時(shí)要求。

private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay. .build(); try { // Copy to customize OkHttp for this request. OkHttpClient copy = client.newBuilder() .readTimeout(500, TimeUnit.MILLISECONDS) .build(); Response response = copy.newCall(request).execute(); System.out.println("Response 1 succeeded: " + response); } catch (IOException e) { System.out.println("Response 1 failed: " + e); } try { // Copy to customize OkHttp for this request. OkHttpClient copy = client.newBuilder() .readTimeout(3000, TimeUnit.MILLISECONDS) .build(); Response response = copy.newCall(request).execute(); System.out.println("Response 2 succeeded: " + response); } catch (IOException e) { System.out.println("Response 2 failed: " + e); } }

3.14 認(rèn)證處理

OkHttp可以自動(dòng)重試未經(jīng)授權(quán)的要求。當(dāng)響應(yīng)是401 Not Authorized,1個(gè)Authenticator被要求提供憑據(jù)。實(shí)現(xiàn)應(yīng)當(dāng)建立1個(gè)包括缺少憑據(jù)的新要求。如果沒有憑證可用,則返回null跳太重試。

使用Response.challenges()取得任何認(rèn)證挑戰(zhàn)方案和領(lǐng)域。當(dāng)完成1個(gè)基本的挑戰(zhàn),用Credentials.basic(username, password)編碼要求頭。

private final OkHttpClient client; public Authenticate() { client = new OkHttpClient.Builder() .authenticator(new Authenticator() { @Override public Request authenticate(Route route, Response response) throws IOException { System.out.println("Authenticating for response: " + response); System.out.println("Challenges: " + response.challenges()); String credential = Credentials.basic("jesse", "password1"); return response.request().newBuilder() .header("Authorization", credential) .build(); } }) .build(); } public void run() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/secrets/hellosecret.txt") .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); }

為了不驗(yàn)證時(shí)不工作的重試,你可以返回null放棄。例如,當(dāng)這些確切的憑據(jù)已嘗試,您可以跳太重試:

if (credential.equals(response.request().header("Authorization"))) { return null; //如果我們已使用這些憑據(jù)失敗,不重試 }

您也能夠跳太重試,當(dāng)你1個(gè)利用嘗試的次數(shù)超過了限制的次數(shù):

if (responseCount(response) >= 3) { return null; //如果我們已失敗了3次,放棄。 . }

這上面的代碼依賴于這個(gè)responseCount()方法:

private int responseCount(Response response) { int result = 1; while ((response = response.priorResponse()) != null) { result++; } return result; }

4、攔截器

攔截器是1個(gè)強(qiáng)大的機(jī)制,它可以監(jiān)控,重寫和重試Calls。下面是記錄傳出要求和響應(yīng)傳入1個(gè)簡(jiǎn)單的攔截器。

class LoggingInterceptor implements Interceptor { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request request = chain.request(); long t1 = System.nanoTime(); logger.info(String.format("Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers())); Response response = chain.proceed(request); long t2 = System.nanoTime(); logger.info(String.format("Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers())); return response; } }

1個(gè)呼喚chain.proceed(request)是每一個(gè)攔截器的實(shí)現(xiàn)的重要組成部份。這個(gè)看起來簡(jiǎn)單的方法是,所有的HTTP工作情況,產(chǎn)生滿足要求的響應(yīng)。

攔截器可以鏈接。假定你有1個(gè)既緊縮攔截器和攔截器校驗(yàn):你需要肯定數(shù)據(jù)是不是被緊縮,然后履行校驗(yàn),或是先校驗(yàn)然后再緊縮。OkHttp使用列表來跟蹤攔截器,為了攔截器被調(diào)用。
這里寫圖片描述

4.1 利用攔截器

攔截器被注冊(cè)為任1利用程序或網(wǎng)絡(luò)攔截器。我們將使用LoggingInterceptor上面定義以示區(qū)分。

注冊(cè)1個(gè)利用程序攔截器通過在OkHttpClient.Builder上調(diào)用addInterceptor()

OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new LoggingInterceptor()) .build(); Request request = new Request.Builder() .url("http://www.publicobject.com/helloworld.txt") .header("User-Agent", "OkHttp Example") .build(); Response response = client.newCall(request).execute(); response.body().close();

該URL http://www.publicobject.com/helloworld.txt重定向到https://publicobject.com/helloworld.txt,并OkHttp遵守這類自動(dòng)重定向。我們的利用程序攔截器被調(diào)用1次,并且從返回的響應(yīng)chain.proceed()具有重定向的回應(yīng):

INFO: Sending request http://www.publicobject.com/helloworld.txt on null User-Agent: OkHttp Example INFO: Received response for https://publicobject.com/helloworld.txt in 1179.7ms Server: nginx/1.4.6 (Ubuntu) Content-Type: text/plain Content-Length: 1759 Connection: keep-alive

我們可以看到,我們被重定向是由于response.request().url()不同于request.url() 。這兩個(gè)日志語句記錄兩個(gè)不同的URL。

4.2 網(wǎng)絡(luò)攔截器

注冊(cè)網(wǎng)絡(luò)攔截器相當(dāng)類似。調(diào)用addNetworkInterceptor()代替addInterceptor()

OkHttpClient client = new OkHttpClient.Builder() .addNetworkInterceptor(new LoggingInterceptor()) .build(); Request request = new Request.Builder() .url("http://www.publicobject.com/helloworld.txt") .header("User-Agent", "OkHttp Example") .build(); Response response = client.newCall(request).execute(); response.body().close();

當(dāng)我們運(yùn)行這段代碼,攔截器運(yùn)行兩次。1個(gè)是初始要求http://www.publicobject.com/helloworld.txt,另外一個(gè)是用于重定向到https://publicobject.com/helloworld.txt。

INFO: Sending request http://www.publicobject.com/helloworld.txt on Connection{www.publicobject.com:80, proxy=DIRECT hostAddress=54.187.32.157 cipherSuite=none protocol=http/1.1} User-Agent: OkHttp Example Host: www.publicobject.com Connection: Keep-Alive Accept-Encoding: gzip INFO: Received response for http://www.publicobject.com/helloworld.txt in 115.6ms Server: nginx/1.4.6 (Ubuntu) Content-Type: text/html Content-Length: 193 Connection: keep-alive Location: https://publicobject.com/helloworld.txt INFO: Sending request https://publicobject.com/helloworld.txt on Connection{publicobject.com:443, proxy=DIRECT hostAddress=54.187.32.157 cipherSuite=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA protocol=http/1.1} User-Agent: OkHttp Example Host: publicobject.com Connection: Keep-Alive Accept-Encoding: gzip INFO: Received response for https://publicobject.com/helloworld.txt in 80.9ms Server: nginx/1.4.6 (Ubuntu) Content-Type: text/plain Content-Length: 1759 Connection: keep-alive

網(wǎng)絡(luò)要求還含有更多的數(shù)據(jù),如OkHttp加入Accept-Encoding: gzip頭部通知支持緊縮響應(yīng)。網(wǎng)絡(luò)攔截器的鏈具有非空的連接,它可用于詢問IP地址和用于連接到網(wǎng)絡(luò)服務(wù)器的TLS配置。

4.3 利用程序和網(wǎng)絡(luò)攔截之間進(jìn)行選擇

每一個(gè)攔截器鏈(interceptor chain)具有相對(duì)優(yōu)勢(shì)。

利用攔截器

  • 沒必要擔(dān)心像重定向和重試的中間響應(yīng)。
  • 總是被調(diào)用1次,即便HTTP響應(yīng)來自緩存服務(wù)。
  • 視察利用程序的原意。不關(guān)心OkHttp注入的頭文件,如 If-None-Match
  • 允許短路和不調(diào)用Chain.proceed()
  • 允許重試,并屢次調(diào)用Chain.proceed() 。

網(wǎng)絡(luò)攔截器

  • 能夠操作像重定向和重試的中間響應(yīng)。
  • 在短路網(wǎng)絡(luò)不調(diào)用的緩存的響應(yīng)。
  • 視察會(huì)在網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)。
  • 訪問Connection承載要求。

4.4重寫要求

攔截器可以添加,刪除或替換要求頭。他們還可以轉(zhuǎn)換要求體。例如,如果你連接到已知支持它的網(wǎng)絡(luò)服務(wù)器,你可使用利用程序攔截器添加要求體的緊縮。

/** This interceptor compresses the HTTP request body. Many webservers can't handle this! */ final class GzipRequestInterceptor implements Interceptor { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request originalRequest = chain.request(); if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) { return chain.proceed(originalRequest); } Request compressedRequest = originalRequest.newBuilder() .header("Content-Encoding", "gzip") .method(originalRequest.method(), gzip(originalRequest.body())) .build(); return chain.proceed(compressedRequest); } private RequestBody gzip(final RequestBody body) { return new RequestBody() { @Override public MediaType contentType() { return body.contentType(); } @Override public long contentLength() { return -1; // We don't know the compressed length in advance! } @Override public void writeTo(BufferedSink sink) throws IOException { BufferedSink gzipSink = Okio.buffer(new GzipSink(sink)); body.writeTo(gzipSink); gzipSink.close(); } }; } }

4.5 重寫響應(yīng)

相對(duì)應(yīng)的,攔截器也能夠重寫響應(yīng)頭和轉(zhuǎn)換響應(yīng)體。這通常不是重寫要求頭,由于它可能違背了Web服務(wù)器的期望致使更危險(xiǎn)!

如果你在1個(gè)辣手的情況下,并做好應(yīng)對(duì)的后果,重寫響應(yīng)頭是解決問題的有效方式。例如,您可以修復(fù)服務(wù)器的配置毛病的Cache-Control響應(yīng)頭以便更好地響應(yīng)緩存:

/** Dangerous interceptor that rewrites the server's cache-control header. */ private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder() .header("Cache-Control", "max-age=60") .build(); } };

通常,此方法效果最好的時(shí)候,它補(bǔ)充了在Web服務(wù)器上相應(yīng)的修復(fù)!

4.6 可用性

OkHttp的攔截器需要OkHttp 2.2或更高。不幸的是,攔截器不能與OkUrlFactory工作,或說建立在其上的庫,包括 Retrofit ≤1.8和 Picasso≤2.4。

5、 HTTPS

OkHttp試圖平衡兩個(gè)相互競(jìng)爭(zhēng)的耽憂:

  • 連接到盡量多的主機(jī)越好。這包括運(yùn)行最新版本的先進(jìn)主機(jī)boringssl和運(yùn)行舊版的日期主機(jī)OpenSSL
  • 安全的連接。這包括遠(yuǎn)程Web服務(wù)器證書的驗(yàn)證和強(qiáng)密碼交換的數(shù)據(jù)隱私。

當(dāng)觸及到HTTPS服務(wù)器的連接,OkHttp需要知道提供哪些TLS版本和密碼套件。如果客戶端想要最大限度地連接包括過時(shí)的TLS版本和弱由設(shè)計(jì)的密碼套件。客戶端想要最大限度地提高安全性,應(yīng)當(dāng)被要求使用最新版本的TLS和實(shí)力最強(qiáng)的加密套件。

具體的安全與連接的決定是由實(shí)行ConnectionSpec接口。OkHttp包括3個(gè)內(nèi)置的連接規(guī)格:

  • MODERN_TLS是連接到現(xiàn)代的HTTPS服務(wù)器安全的配置。
  • COMPATIBLE_TLS是連接到1個(gè)安全,但不是現(xiàn)代的-HTTPS服務(wù)器的安全配置。
  • CLEARTEXT是用于不安全配置的http://網(wǎng)址。
    默許情況下,OkHttp將嘗試MODERN_TLS連接,如果現(xiàn)代配置失敗的話將退回到COMPATIBLE_TLS連接。

在每個(gè)規(guī)范的TLS版本和密碼套件可隨每一個(gè)發(fā)行版而更改。例如,在OkHttp 2.2,我們降落支持響應(yīng)POODLE攻擊的SSL 3.0。而在OkHttp 2.3我們降落的支持RC4。與桌面Web閱讀器,保持最新的OkHttp是保持安全的最好辦法。

你可以用1組自定義TLS版本和密碼套件建立自己的連接規(guī)格。例如,這類配置限制為3個(gè)備受推重的密碼套件。它的缺點(diǎn)是,它需要的Andr??oid 5.0+和1個(gè)類似的電流網(wǎng)絡(luò)服務(wù)器

ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) .tlsVersions(TlsVersion.TLS_1_2) .cipherSuites( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) .build(); OkHttpClient client = new OkHttpClient.Builder() .connectionSpecs(Collections.singletonList(spec)) .build();

5.1證書釘扎

默許情況下,OkHttp信任主機(jī)平臺(tái)的證書頒發(fā)機(jī)構(gòu)。這類策略最多的連接,但它受證書頒發(fā)機(jī)構(gòu)的攻擊,如2011 DigiNotar的攻擊。它還假定您的HTTPS服務(wù)器的證書是由證書頒發(fā)機(jī)構(gòu)簽署。

使用CertificatePinner來限制哪些證書和證書頒發(fā)機(jī)構(gòu)是可信任的。證書釘扎增強(qiáng)了安全性,但限制你的服務(wù)器團(tuán)隊(duì)的能力來更新自己的TLS證書。在沒有你的服務(wù)器的TLS管理員的同意下,不要使用證書釘扎!

public CertificatePinning() { client = new OkHttpClient.Builder() .certificatePinner(new CertificatePinner.Builder() .add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") .build()) .build(); } public void run() throws Exception { Request request = new Request.Builder() .url("https://publicobject.com/robots.txt") .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); for (Certificate certificate : response.handshake().peerCertificates()) { System.out.println(CertificatePinner.pin(certificate)); } }

5.2定制信任證書

完全的代碼示例顯示了如何用自己的1套替換主機(jī)平臺(tái)的證書頒發(fā)機(jī)構(gòu)。如上所述,在沒有你的服務(wù)器的TLS管理員的同意下,不要使用自定義證書!

private final OkHttpClient client; public CustomTrust() { SSLContext sslContext = sslContextForTrustedCertificates(trustedCertificatesInputStream()); client = new OkHttpClient.Builder() .sslSocketFactory(sslContext.getSocketFactory()) .build(); } public void run() throws Exception { Request request = new Request.Builder() .url("https://publicobject.com/helloworld.txt") .build(); Response response = client.newCall(request).execute(); System.out.println(response.body().string()); } private InputStream trustedCertificatesInputStream() { ... // Full source omitted. See sample. } public SSLContext sslContextForTrustedCertificates(InputStream in) { ... // Full source omitted. See sample. }
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 免费午夜视频在线观看 | 欧美高清在线视频在线99精品 | 亚洲视色| 欧美成人观看免费全部完小说 | 曰本www| 欧美极品jiizzhd欧美 | 国产逼逼 | 国产免费福利视频一区二区 | 亚洲线精品一区二区三区 | 亚洲成人av| 精品久久久久久午夜 | 91久久人澡人人添人人爽 | 欧美一区二区在线观看视频 | 欧美日韩在线观看免费 | 日韩手机在线观看 | 国产精品欧美一区二区三区不卡 | 毛片在线不卡 | 精品综合 | 亚洲久久影院 | 欧美在线精品永久免费播放 | 欧美三级超在线视频 | 成人精品一区二区久久久 | 中文字幕不卡一区 二区三区 | 亚洲性hd| 日本欧美一区二区三区乱码 | 极品久久 | 色干综合 | 欧美xxxx极品流血 | 亚洲综合图片小说 | 欧美三级大片在线观看 | 国产三级精品在线观看 | 国产日韩欧美精品一区二区三区 | 欧美啊啊 | 亚洲视频免费在线看 | 永久手机看片福利盒子 | 日本番囗 | 中文字幕精品视频 | 亚洲国产成a人v在线观看 | 日本久久影视 | 99精品视频在线成人精彩视频 | 性欧美videos另类hd高清 |