日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > OkHttp 官方中文文檔

OkHttp 官方中文文檔

來源:程序員人生   發布時間:2016-07-13 10:18:30 閱讀次數:3395次

OkHttp官方中文文檔

本文結構

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

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

1、Calls

HTTP客戶真個工作是接受你的request,并產生它的response。這個在理論上是簡單的,但在實踐中確是很辣手。

1.1 要求

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

1.2 響應

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

1.3重寫要求

當你的OkHttp發送1個HTTP要求,你在描寫1個高層次的要求:“給我獲得這個網址中的這些要求頭。”對正確性和效力,OkHttp發送前會重寫你的要求。

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

1些要求會有1個緩存的響應。當這個緩存的響應不是最新的,OkHttp會發送1個有條件的GET來下載更新的響應,如果它比緩存還新。它將會添加需要的要求頭,如IF-Modified-SinceIf-None-Match

1.4重寫響應

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

如果1個條件GET是成功的,在唆使的規范下響應來自于網絡和緩存的合并。

1.5后續要求

當你的要求的URL已移動,Web服務器將返回1個響應碼像302,以表明本文檔的新的URL。OkHttp將依照重定向檢索的終究響應。

如果響應問題是1個的授權盤問,OkHttp將會要求身份驗證(如果有1個已配置好),以滿足盤問。如果身份驗證提供憑據,要求將會帶著憑證進行重試。

1.6要求重試

有時連接失敗:要末是連接池已過時和斷開,或是Web服務器本身沒法達成。如果有1個是可用的,OkHttp將會使用不同的路由進行要求重試。

1.7 呼喚

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

通過以下兩種方式進行呼喚:
- 同步:直到響應,你的線程塊是可讀的。
- 異步:你在任何線程進行排隊要求,并且當響應是可讀的時候,你會在另外一個線程得到回調。

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

1.8調度

對同步調用,你帶上你自己的線程,并負責管理并發要求。并發連接過量浪費資源; 過少的危害等待時間。

對異步調用,調度實現了最大同時要求策略。您可以設置每一個Web服務器最大值(默許值為5),和整體(默許為64)。

2、Connections

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

2.1URLs

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

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

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

2.2 Addresses

Addresses指定網絡服務器(如github.com)和所有的靜態必要的配置,和連接到該服務器:端口號,HTTPS設置和首選的網絡協議(如HTTP / 2SPDY)。

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

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

2.3 Routes

Routes提供連接到1個網絡服務器所必須的動態信息。就是嘗試特定的IP地址(如由DNS查詢發現),使用確切的代理服務器(如果1個特定的IP地址的ProxySelector在使用中)和協商的TLS版本(HTTPS連接)。

可能有單個地址對應多個路由。例如,在多個數據中心托管的Web服務器,它可能會在其DNS響應產生多個IP地址。

2.4Connections

當你使用OkHttp進行1個URL要求,下面是它的操作流程:

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

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

3、Recipes

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

3.1同步獲得

下載文件,打印其頭部,并以字符串情勢打印其響應體。

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

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個工作線程的文件,當響應是可讀的時候,獲得回調(Callback)。當響應頭已準備好后,將產生回調(Callback)。讀取響應體可能1直阻塞。目前OkHttp不提供異步API來接收響應體的部位。

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個Map<String, String> :每一個字段都有1個值或無值。但是,1些頭部(headers)允許多個值,比如Guava的Multimap。例如,它共同為1個HTTP響應提供多個Vary頭。OkHttp的API,試圖使這兩種情況下都能舒適使用。

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

當讀取響應頭,用header(name)返回最后設置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的要求體發送到服務。下面例子post了1個markdown文檔到1個的Web服務(將markdown作為HTML)。由于全部要求體是同時在內存中,應避免使用此API發送較大(大于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。正在生成要求體的內容寫入到stream中。下面例子streams直接進入 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 發布表單參數

使用FormBody.Builder建立1個要求體,它就像1個HTML 的標記。Namesvalues將使用HTML兼容的表單URL編碼進行編碼。

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 發布multipart要求

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

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解析響應的JSON

GSON是1個JSON和Java對象之間的便利轉換的API。這里,我們用它來解碼從GitHub的API 響應的JSON。

需要注意的是ResponseBody.charStream()使用的Content-Type響應頭進行解碼時,所使用的字符集,如果沒有指定字符集,它默許為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 響應緩存

要緩存響應,你需要1個緩存目錄來進行讀取和寫入,和1個緩存的大小限制。緩存目錄應當是私有的,不信任的利用程序不應當能夠瀏覽其內容!

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

響應緩存使用HTTP頭的所有配置。您可以添加要求頭Cache-Control: max-stale=3600和OkHttp的緩存會遵守他們。你的網絡服務器可以通過自己的響應頭配置多長時間緩存響應,如Cache-Control: max-age=9600。有緩存頭強迫緩存的響應,強迫網絡響應,或強迫使用條件GET驗證的網絡響應。

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)); }

為了避免使用緩存的響應,使用CacheControl.FORCE_NETWORK。為了避免它使用網絡,使用CacheControl.FORCE_CACHE。正告:如果您使用FORCE_CACHE和響應要求網絡,OkHttp將會返回1個504不可滿足要求的響應。

3.11 取消Call

使用Call.cancel()立即停止正在進行的Call。如果1個線程目前正在寫要求或讀響應,它還將收到1個IOException異常。當1個Call不需要時,使用此保護網絡; 例如,當用戶從利用程序導航離開。同步和異步調用可以被取消。

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 超時

當其查詢沒法訪問時,使用超時失敗的調用。網絡劃分可以是由于客戶端連接問題,服務器可用性的問題,或之間的任何東西。OkHttp支持連接,讀取和寫入超時。

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 每一個呼喚配置

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

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 認證處理

OkHttp可以自動重試未經授權的要求。當響應是401 Not Authorized,1個Authenticator被要求提供憑據。實現應當建立1個包括缺少憑據的新要求。如果沒有憑證可用,則返回null跳太重試。

使用Response.challenges()取得任何認證挑戰方案和領域。當完成1個基本的挑戰,用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()); }

為了不驗證時不工作的重試,你可以返回null放棄。例如,當這些確切的憑據已嘗試,您可以跳太重試:

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

您也能夠跳太重試,當你1個利用嘗試的次數超過了限制的次數:

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

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

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

4、攔截器

攔截器是1個強大的機制,它可以監控,重寫和重試Calls。下面是記錄傳出要求和響應傳入1個簡單的攔截器。

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個呼喚chain.proceed(request)是每一個攔截器的實現的重要組成部份。這個看起來簡單的方法是,所有的HTTP工作情況,產生滿足要求的響應。

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

4.1 利用攔截器

攔截器被注冊為任1利用程序或網絡攔截器。我們將使用LoggingInterceptor上面定義以示區分。

注冊1個利用程序攔截器通過在OkHttpClient.Builder上調用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遵守這類自動重定向。我們的利用程序攔截器被調用1次,并且從返回的響應chain.proceed()具有重定向的回應:

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() 。這兩個日志語句記錄兩個不同的URL。

4.2 網絡攔截器

注冊網絡攔截器相當類似。調用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();

當我們運行這段代碼,攔截器運行兩次。1個是初始要求http://www.publicobject.com/helloworld.txt,另外一個是用于重定向到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

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

4.3 利用程序和網絡攔截之間進行選擇

每一個攔截器鏈(interceptor chain)具有相對優勢。

利用攔截器

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

網絡攔截器

  • 能夠操作像重定向和重試的中間響應。
  • 在短路網絡不調用的緩存的響應。
  • 視察會在網絡上傳輸的數據。
  • 訪問Connection承載要求。

4.4重寫要求

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

/** 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 重寫響應

相對應的,攔截器也能夠重寫響應頭和轉換響應體。這通常不是重寫要求頭,由于它可能違背了Web服務器的期望致使更危險!

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

/** 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(); } };

通常,此方法效果最好的時候,它補充了在Web服務器上相應的修復!

4.6 可用性

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

5、 HTTPS

OkHttp試圖平衡兩個相互競爭的耽憂:

  • 連接到盡量多的主機越好。這包括運行最新版本的先進主機boringssl和運行舊版的日期主機OpenSSL
  • 安全的連接。這包括遠程Web服務器證書的驗證和強密碼交換的數據隱私。

當觸及到HTTPS服務器的連接,OkHttp需要知道提供哪些TLS版本和密碼套件。如果客戶端想要最大限度地連接包括過時的TLS版本和弱由設計的密碼套件。客戶端想要最大限度地提高安全性,應當被要求使用最新版本的TLS和實力最強的加密套件。

具體的安全與連接的決定是由實行ConnectionSpec接口。OkHttp包括3個內置的連接規格:

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

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

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

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信任主機平臺的證書頒發機構。這類策略最多的連接,但它受證書頒發機構的攻擊,如2011 DigiNotar的攻擊。它還假定您的HTTPS服務器的證書是由證書頒發機構簽署。

使用CertificatePinner來限制哪些證書和證書頒發機構是可信任的。證書釘扎增強了安全性,但限制你的服務器團隊的能力來更新自己的TLS證書。在沒有你的服務器的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套替換主機平臺的證書頒發機構。如上所述,在沒有你的服務器的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. }
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 麻豆av免费在线观看 | 精品视频首页 | 精品一区精品二区 | 成人久久久久 | 欧美电影一区二区三区 | 99热.com| 在线一区二区视频 | 欧美韩国日本一区二区三区 | 最新日韩在线观看视频 | 美女激情网站 | 日本不卡免费新一二三区 | 最新国产精品精品视频 | 日韩视频一区二区 | 成人一区二区三区 | 亚洲精选一区 | 麻豆一二三区 | 精品国产三级 | 黄色在线观看免费视频 | 成人在线黄色 | 久久久久免费网站 | 99午夜 | 国产精品久久久久一区二区 | 中文字幕精品亚洲 | 久久久久久国产精品 | 亚洲国产一区二区三区 | 91精品国产福利一区二区三区 | 亚洲国产精品成人 | 一世独尊动漫在线观看 | 久久久久99| 国产热re99久久6国产精品 | 91免费影片| 91久久久久久久一区二区 | 色婷婷久久一区二区三区麻豆 | 国产视频一区在线观看 | 日韩欧美大片 | 日韩午夜视频在线观看 | 黄色成人在线视频 | 久久亚洲一区 | 精品一区久久久 | 欧美日韩国产一区 | 国产日韩精品久久 |