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分析筆記