Android OkhttpInterceptor 筆記:BridgeInterceptor

Anroid OKhttp筆記1 流程分析
Android OkhttpInterceptor 筆記:RetryAndFollowUpInterceptor
Android OkhttpInterceptor 筆記:BridgeInterceptor
Android OkhttpInterceptor 筆記:ConnectInterceptor
Android OkhttpInterceptor 筆記:CacheInterceptor
Android OkhttpInterceptor 筆記:CallServerInterceptor
Android Okhttp筆記:ConnectionPool
Android Okhttp3:Dispatcher分析筆記


一、綜述

1.概念

橋接(Bridge)是用于把抽象化與實(shí)現(xiàn)化解耦,使得二者可以獨(dú)立變化。
BridgeInterceptor是一個(gè)處理請(qǐng)求與返回的攔截器,它會(huì)對(duì)請(qǐng)求的Header進(jìn)行一些處理,然后將工作交到下一級(jí)Interceptor,下一級(jí)完成后,再對(duì)返回進(jìn)行處理。

2.作用

BridgeInterceptor 攔截器的功能主要有以下 3 點(diǎn):

1.是負(fù)責(zé)將用戶構(gòu)建的一個(gè) Request 請(qǐng)求轉(zhuǎn)化為能夠進(jìn)行網(wǎng)絡(luò)訪問的請(qǐng)求。
2.將這個(gè)符合網(wǎng)絡(luò)請(qǐng)求的 Request 進(jìn)行網(wǎng)絡(luò)請(qǐng)求。
3.將網(wǎng)絡(luò)請(qǐng)求回來的響應(yīng) Response 轉(zhuǎn)化為用戶可用的 Response。

二、源碼

     @Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();

RequestBody body = userRequest.body();
if (body != null) {
  MediaType contentType = body.contentType();
  if (contentType != null) {
    requestBuilder.header("Content-Type", contentType.toString());
  }

  long contentLength = body.contentLength();
  if (contentLength != -1) {
    requestBuilder.header("Content-Length", Long.toString(contentLength));
    requestBuilder.removeHeader("Transfer-Encoding");
  } else {
    requestBuilder.header("Transfer-Encoding", "chunked");
    requestBuilder.removeHeader("Content-Length");
  }
}

if (userRequest.header("Host") == null) {
  requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}

if (userRequest.header("Connection") == null) {
  requestBuilder.header("Connection", "Keep-Alive");
}

// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
//如果我們添加一個(gè)“Accept-Encoding:gzip”頭字段,我們也負(fù)責(zé)解壓縮傳輸流。

boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
  transparentGzip = true;
  requestBuilder.header("Accept-Encoding", "gzip");
}

List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
  requestBuilder.header("Cookie", cookieHeader(cookies));
}

if (userRequest.header("User-Agent") == null) {
  requestBuilder.header("User-Agent", Version.userAgent());
}

Response networkResponse = chain.proceed(requestBuilder.build());
  //解析服務(wù)器返回的Header,如果沒有這個(gè)cookie,則不進(jìn)行解析
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

Response.Builder responseBuilder = networkResponse.newBuilder()
    .request(userRequest);
//判斷服務(wù)器是否支持gzip壓縮,如果支持,則將壓縮提交給Okio庫來處理
if (transparentGzip
    && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
    && HttpHeaders.hasBody(networkResponse)) {
  GzipSource responseBody = new GzipSource(networkResponse.body().source());
  Headers strippedHeaders = networkResponse.headers().newBuilder()
      .removeAll("Content-Encoding")
      .removeAll("Content-Length")
      .build();
  responseBuilder.headers(strippedHeaders);
  String contentType = networkResponse.header("Content-Type");
  responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}

return responseBuilder.build();
}

三、分析

過程并不復(fù)雜,BridgeInterceptor是一個(gè)連接橋,它負(fù)責(zé)把用戶構(gòu)造的請(qǐng)求轉(zhuǎn)換為發(fā)送給服務(wù)器的請(qǐng)求,把服務(wù)器返回的響應(yīng)轉(zhuǎn)換為對(duì)用戶友好的響應(yīng)。
轉(zhuǎn)換的過程就是添加一些服務(wù)端需要的header信息。
在Request階段配置用戶信息,并添加一些請(qǐng)求頭。在Response階段,進(jìn)行g(shù)zip解壓。

1.cookieJar

BridgeInterceptor初始化方法中也實(shí)例了cookieJar,cookieJar就是個(gè)接口,里面有兩個(gè)方法:

saveFromResponse 自定義去存儲(chǔ)cookie
loadForRequest 獲取指定URL的cookie

2.關(guān)于"Accept-Encoding",

如果Response是gzip模式且transparentGzip為true且HttpHeaders.hasBody為true時(shí),會(huì)去掉Headers中的"Content-Encoding"和"Content-Length"。

開發(fā)者沒有添加Accept-Encoding時(shí),自動(dòng)添加Accept-Encoding: gzip

當(dāng)用戶未設(shè)置Accep-Encoding時(shí),用戶期望的Content-Length是返回的內(nèi)容長度。但由于okhttp在用戶未設(shè)置Accep-Encoding時(shí),會(huì)進(jìn)行g(shù)zip的轉(zhuǎn)換。當(dāng)HTTP使用gzip方式時(shí),Content-Length的返回是根據(jù)gzip壓縮后的長度進(jìn)行返回的。此時(shí)Content-Length的值與用戶所期望的不符的。因?yàn)橛脩舨]有主動(dòng)使用gzip模式。

所以,此時(shí)okhttp選擇將Content-Length remove掉,以免讓調(diào)用者產(chǎn)生誤解。


Anroid OKhttp筆記1 流程分析
Android OkhttpInterceptor 筆記:RetryAndFollowUpInterceptor
Android OkhttpInterceptor 筆記:BridgeInterceptor
Android OkhttpInterceptor 筆記:ConnectInterceptor
Android OkhttpInterceptor 筆記:CacheInterceptor
Android OkhttpInterceptor 筆記:CallServerInterceptor
Android Okhttp筆記:ConnectionPool
Android Okhttp3:Dispatcher分析筆記

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 自己備忘,隨便寫 android網(wǎng)絡(luò)框架源碼解析及對(duì)比 android常用網(wǎng)絡(luò)框架對(duì)比 Volley: 特點(diǎn) 基于...
    幻海流心閱讀 1,691評(píng)論 0 4
  • 六談這個(gè)話題,是因?yàn)楹芏鄷r(shí)間都忽略了這個(gè)因素,網(wǎng)絡(luò)傳輸數(shù)據(jù)的壓縮很少有人去關(guān)注,然而有時(shí)間提到這個(gè)問題的時(shí)間卻一時(shí)...
    Eric_feng閱讀 5,714評(píng)論 0 4
  • API定義規(guī)范 本規(guī)范設(shè)計(jì)基于如下使用場(chǎng)景: 請(qǐng)求頻率不是非常高:如果產(chǎn)品的使用周期內(nèi)請(qǐng)求頻率非常高,建議使用雙通...
    有涯逐無涯閱讀 2,927評(píng)論 0 6
  • 流程分析 我們從一個(gè)簡(jiǎn)單的 HTTP 請(qǐng)求開始: 上面的代碼將會(huì)發(fā)起兩個(gè)簡(jiǎn)單的 HTTP 請(qǐng)求,請(qǐng)求流程如下圖所示...
    張可_閱讀 952評(píng)論 0 2
  • 點(diǎn)燃了祖國的太陽 “9?10”懷想 趙明月 在時(shí)代的風(fēng)景線上 有你栽培的桃李 在蔚藍(lán)的九重天宇 有你放飛的雄鷹 你...
    皖南醫(yī)學(xué)院閱讀 131評(píng)論 0 0

友情鏈接更多精彩內(nèi)容