對於Okhttp的使用,不能僅限於「會」用,而是要了解其原理。在嘗試瞭解原理的過程當中,查到 攔截器的概念。java
攔截器是OkHttp 執行網絡請求中的重要角色,貫穿了整個請求執行的過程。(注:okhttp2.2之後纔有攔截器的概念,2.2之後通過了一次代碼重構,加入了攔截器機制)android
爲了瞭解攔截器,閱讀 官方文檔是必不可少的步驟,地址以下:https://github.com/square/okhttp/wiki/Interceptors git
本文主要將官方文檔中的重要概念,以及重要段落的翻譯一一寫明,可能有翻譯的不周到的地方,見諒。github
下圖是okhttp工做流程圖web
能夠看出,Interceptor貫穿了整個請求過程,是在請求執行過程當中扮演重要角色。api
這是okhttp的請求執行過程,從應用發出request,到應用收到response,期間經歷了N個攔截器。網絡
來自官網的英文原文:app
Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.
意思大概是,攔截器是一個強有力的機制,可以監控,重寫以及重試(請求的)調用。異步
如下是官網提供的一個Interceptor例子,只用來打印攔截到的Response的相關日誌:ide
1 class LoggingInterceptor implements Interceptor { 2 String tag = "MainActivityXXXX"; 3
4 @Override 5 public Response intercept(Interceptor.Chain chain) throws IOException { 6 Request request = chain.request(); 7
8 long t1 = System.nanoTime(); 9 Log.d(tag, String.format("Sending request %s on %s%n%s", 10 request.url(), chain.connection(), request.headers())); 11
12 Response response = chain.proceed(request); 13
14 long t2 = System.nanoTime(); 15 Log.d(tag, String.format("Received response for %s in %.1fms%n%s", 16 response.request().url(), (t2 - t1) / 1e6d, response.headers())); 17
18 return response; 19 } 20 }
只是一個Interceptor太抽象,下面我經過一個具體的Activity展現攔截器的用法:
1 package com.test.hank.test2; 2
3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.util.Log; 6
7 import java.io.IOException; 8
9 import okhttp3.Call; 10 import okhttp3.Callback; 11 import okhttp3.Interceptor; 12 import okhttp3.OkHttpClient; 13 import okhttp3.Request; 14 import okhttp3.Response; 15
16 public class Main2Activity extends Activity { 17
18 @Override 19 protected void onCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main2); 22 testAsyncGetRequest(); 23 } 24
25 private static final String tag = "main2tag"; 26 private static final String url = "http://www.publicobject.com/helloworld.txt"; 27
28 //這是一個普通的okhttp異步get請求
29 private void testAsyncGetRequest() { 30 OkHttpClient okHttpClient = new OkHttpClient().newBuilder().addInterceptor(new LoggingInterceptor()).build();//新建一個okhttpClient對象,而且設置攔截器
31 Request request = new Request.Builder().url(url).build();//新建Request對象
32 Callback callback = new Callback() {// 新建異步請求的回調函數
33 @Override 34 public void onFailure(Call call, IOException e) { 35 Log.d(tag, "request Failed ; " + e.getLocalizedMessage()); 36 } 37
38 @Override 39 public void onResponse(Call call, Response response) throws IOException { 40 if (response.isSuccessful()) { 41 Log.d(tag, "onResponse:" + response.body().string()); 42 } else { 43 Log.d(tag, "onResponse failed"); 44 } 45 } 46 }; 47 okHttpClient.newCall(request).enqueue(callback);//用okhttpClient執行request,而且註冊回調函數
48
49 } 50
51
52 /**
53 * 這是按照官方的示例Interceptor改的,打印日誌的方式換成了Log.d(). 54 */
55 class LoggingInterceptor implements Interceptor { 56
57 @Override 58 public Response intercept(Chain chain) throws IOException { 59 //第一步,得到chain內的request
60 Request request = chain.request(); 61 Log.d(tag, "intercept-request:" + request.url()); 62 //第二步,用chain執行request
63 Response response = chain.proceed(request); 64 Log.d(tag, "intercept-response" + "-" + response.request().url()); 65 //第三步,返回response
66 return response; 67 } 68 } 69 }
對照最上方的Okhttp工做流程圖,能夠觀察到,在OkhttpCore即將把response返回給application時,攔截器率先獲得了response對象。而在上方的代碼中,只是對request和response進行了日誌打印,並無實際操做。
可是事實上,攔截器拿到了request以後,能夠對request進行重寫,能夠添加,移除,替換請求頭,也能對response的header進行重寫,改變response的body。佐證以下,文檔英文原文:
Rewriting Requests Interceptors can add, remove, or replace request headers. They can also transform the body of those requests that have one. For example, you can use an application interceptor to add request body compression if you're connecting to a webserver known to support it.
Rewriting Responses Symmetrically, interceptors can rewrite response headers and transform the response body. This is generally more dangerous than rewriting request headers because it may violate the webserver's expectations!
上面的Activity運行起來以後,能夠在日誌中看到以下內容:證實,攔截器確實能夠得到response。
04-03 22:54:17.918 11961-12042/com.test.hank.test2 D/main2tag: intercept-request:http://www.publicobject.com/helloworld.txt
04-03 22:54:21.134 11961-12042/com.test.hank.test2 D/main2tag: intercept-response-https://publicobject.com/helloworld.txt
04-03 22:54:21.142 11961-12042/com.test.hank.test2 D/main2tag: onResponse: \\ // \\ .ooo. // .@@@@@@@@@. :@@@@@@@@@@@@@: :@@. '@@@@@' .@@: @@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@
.......
綜上所述,攔截器的做用就是:能夠在應用拿到response以前,先得到response,對其中某些數據進行監控,在有必要的狀況下,對response的某些內容(好比response的header,body,response內的request的header,body)進行更改。
(至於過高深的攔截器用法,筆者能力有限,只能研究到這裏,有緣分的話,再深刻研究)。
okhttp工做流程圖中,橙色框框內的那些攔截器,屬於okhttp庫內部定義的,通常狀況下不會更改。因此這裏只討論開發者可以自定義的攔截器。
分爲兩類:
1)ApplicationInterceptor(應用攔截器)
2)NetworkInterceptor(網絡攔截器)
他們的異同:
相同點,
1)都能對server返回的response進行攔截(好像是廢話···)
2)這兩種攔截器本質上都是基於Interceptor接口,由開發者實現這個接口,而後將自定義的Interceptor類的對象設置到okhttpClient對象中(參見上面的Main2Activity代碼)。因此,他們的對象,本質上沒什麼不一樣,都是Interceptor的實現類的對象。
3)二者都會被add到OkHttpClient內的一個ArrayList中。當請求執行的時候,多個攔截器會依次執行(list自己就是有序的)。
不一樣點,
1)okhttpClient添加兩種攔截器的api不一樣。添加應用攔截器的接口是addInterceptor(),而添加網絡攔截器的接口是addNetworkInterceptor().
2)二者負責的區域不一樣,從最上方圖中能夠看出,應用攔截器做用於okhttpCore到Application之間,網絡攔截器做用於 network和okhttpCore之間
3)在某種特殊狀況下(好比:訪問了一個url,結果這個url發生了重定向),網絡攔截器有可能被執行屢次,可是 不論任何狀況,application只會被執行一次。(這個,證實起來十分簡單,只須要將上面代碼中30行的addInterceptor改爲addNetworkInterceptor,運行起來再觀察日誌打印,就會發現,內容被打印了兩次,我就再也不試了,有興趣的可本身運行代碼)
其實官方文檔中,對兩種攔截器的異同作了更標準的說明,可是我翻譯了一下以爲一臉懵逼,因此就本身總結了以上的幾點異同,可是官方的說明我仍是貼在下面。
Choosing between application and network interceptors Each interceptor chain has relative merits. Application interceptors Don't need to worry about intermediate responses like redirects and retries. Are always invoked once, even if the HTTP response is served from the cache. Observe the application's original intent. Unconcerned with OkHttp-injected headers like If-None-Match. Permitted to short-circuit and not call Chain.proceed(). Permitted to retry and make multiple calls to Chain.proceed().
Network Interceptors Able to operate on intermediate responses like redirects and retries. Not invoked for cached responses that short-circuit the network. Observe the data just as it will be transmitted over the network. Access to the Connection that carries the request.
就說到這裏吧,以上內容都是本身根據官方文檔加上本身作實驗得出的確切的結論。能寫出來的都是本身的淺顯理解,不求裝B,只求能說明白,讓人讀起來暢通,好理解。
下一篇準備研究一下,okhttp對於https請求的處理。