根據(jù)Interceptor 分析 OkHttp(二)

Interceptor OkHttp


Interceptor可以說是OkHttp的核心功能郎汪,它就是通過Interceptor來完成監(jiān)控管理嚼蚀、重寫和重試請求的翩伪。下面是一個簡單的Interceptor轰枝,可以監(jiān)控request的輸入?yún)?shù)和response的輸出內容拧簸。

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

里面有個方法調用chain.proceed(request),每個Interceptor實現(xiàn)里都有這個調用方法燕少,這個看起來簡單的方法卻是所有的HTTP請求卡者、生成response的關鍵所在。

Interceptors可以被串聯(lián)起來(chained)客们。OkHttp使用lists來管理Interceptors,讓這些Interceptors按順序被調用崇决。

Interceptors Diagram
Interceptors Diagram

Application Interceptors

我們只能通過Application Interceptors或者Network Interceptors來注冊自定義的Interceptors,其他Interceptors都是OkHttp幫你做好了的底挫,比如RetryAndFollowUpInterceptor恒傻、BridgeInterceptor、CacheInterceptor凄敢、ConnectInterceptor碌冶、CallServerInterceptor。這里的OkHttp會啟動一個攔截器調用鏈涝缝,攔截器遞歸調用之后最后返回請求的響應Response扑庞。這里的攔截器分層的思想就是借鑒的網(wǎng)絡里的分層模型的思想。請求從最上面一層到最下一層拒逮,響應從最下一層到最上一層罐氨,每一層只負責自己的任務,對請求或響應做自己負責的那塊的修改滩援。

Interceptors Diagram
Interceptors Diagram

Application Interceptors和Network Interceptors分別位于七層模型的第一層和第六層栅隐。這個從RealCall里的getResponseWithInterceptorChain方法中就可以看出來:

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors()); // Application Interceptors
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors()); // Network Interceptors
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

我們通過這個LoggingInterceptor 來說明Application Interceptors和Network Interceptors的區(qū)別。

通過OkHttpClient.BuilderaddInterceptor()注冊一個 application interceptor:

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會自動follow這次重定向玩徊。application interceptor會被調用once租悄,并且會返回攜帶有重定向后的redirected response。

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

我們可以看到恩袱,會重定向是因我request的URL和response的URL是不同的泣棋,日志也打印了兩個不同的URLs。

Network Interceptors

注冊一個Network Interceptors的方式是非常類似的畔塔,只需要將addInterceptor()替換為addNetworkInterceptor()

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

當我們執(zhí)行上面這段代碼潭辈,這個interceptor會執(zhí)行twice。一次是調用在初始的request http://www.publicobject.com/helloworld.txt澈吨,另外一次是調用在重定向后的redirect request 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

Application and Network interceptors 該如何選擇

這兩個interceptor都有他們各自的優(yōu)缺點:

Application Interceptors

  • 不需要關心由重定向、重試請求等造成的中間response產(chǎn)物谅辣。
  • 總會被調用一次修赞,即使HTTP response是從緩存(cache)中獲取到的。
  • 關注原始的request桑阶,而不關心注入的headers榔组,比如If-None-Match熙尉。
  • interceptor可以被取消調用,不調用Chain.proceed()搓扯。
  • interceptor可以重試和多次調用Chain.proceed()

Network Interceptors

  • 可以操作由重定向包归、重試請求等造成的中間response產(chǎn)物锨推。
  • 如果是從緩存中獲取cached responses ,導致中斷了network公壤,是不會調用這個interceptor的换可。
  • 數(shù)據(jù)在整個network過程中都可以通過Network Interceptors監(jiān)聽。
  • 可以獲取攜帶了request的Connection厦幅。

使用Interceptor的說明

在OkHttp 2.2版本才加入了Interceptor功能沾鳄,而且,Interceptor不能使用OkUrlFactory确憨,或者是基于OkHttp的低版本第三方庫译荞,比如Retrofit ≤ 1.8 and Picasso ≤ 2.4 。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末休弃,一起剝皮案震驚了整個濱河市吞歼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌塔猾,老刑警劉巖篙骡,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異丈甸,居然都是意外死亡糯俗,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門睦擂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來得湘,“玉大人,你說我怎么就攤上這事祈匙『龉簦” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵夺欲,是天一觀的道長跪帝。 經(jīng)常有香客問我,道長些阅,這世上最難降的妖魔是什么伞剑? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮市埋,結果婚禮上黎泣,老公的妹妹穿的比我還像新娘恕刘。我一直安慰自己,他們只是感情好抒倚,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布褐着。 她就那樣靜靜地躺著,像睡著了一般托呕。 火紅的嫁衣襯著肌膚如雪含蓉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天项郊,我揣著相機與錄音馅扣,去河邊找鬼。 笑死着降,一個胖子當著我的面吹牛差油,可吹牛的內容都是我干的。 我是一名探鬼主播任洞,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蓄喇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了侈咕?” 一聲冷哼從身側響起公罕,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎耀销,沒想到半個月后楼眷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡熊尉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年罐柳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狰住。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡张吉,死狀恐怖,靈堂內的尸體忽然破棺而出催植,到底是詐尸還是另有隱情肮蛹,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布创南,位于F島的核電站伦忠,受9級特大地震影響,放射性物質發(fā)生泄漏稿辙。R本人自食惡果不足惜昆码,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赋咽,春花似錦旧噪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至亦镶,卻和暖如春日月,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缤骨。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尺借,地道東北人绊起。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像燎斩,于是被迫代替她去往敵國和親虱歪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容

  • Interceptors are a powerful mechanism that can monitor, r...
    漢之風云閱讀 50,375評論 9 98
  • 這篇文章主要講 Android 網(wǎng)絡請求時所使用到的各個請求庫的關系栅表,以及 OkHttp3 的介紹笋鄙。(如理解有誤,...
    小莊bb閱讀 1,159評論 0 4
  • 緩存的一般思路 下面是我理解的網(wǎng)絡請求框架的緩存基本實現(xiàn)怪瓶。大致的過程是有緩存用緩存的數(shù)據(jù)萧落,沒緩存發(fā)起http請求取...
    原件閱讀 2,808評論 3 12
  • 也許某天見面,你我已是形同陌路的陌生人洗贰,也許今后的路很難找岖,但還是要咬牙過去,人生或許會很難熬下去敛滋,但還是要堅持许布,也...
    也許Y閱讀 117評論 1 1
  • 人有夢想總是好的,萬一實現(xiàn)了呢……我的夢想是想擁有一家自己的小店 绎晃, 灰色的地蜜唾;白色的墻; 原木的擺設庶艾;幻想著親手...
    娜片森林閱讀 213評論 0 1