啊,手廢了,廢了~
第一篇講的是同步、異步調(diào)用源碼走向Android-OKHTTP底層原理淺析(一)
第二篇講的是重定向攔截器、橋攔截器的工作內(nèi)容Android-OKHttp底層原理淺析(二)
第三篇講的是緩存攔截器、連接攔截器的工作內(nèi)容Android-OKhttp底層原理淺析(三)
開擼!CallServerInterceptor——呼叫服務(wù)攔截器
@Override public Response intercept(Chain chain) throws IOException {
HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
Request request = chain.request();
long sentRequestMillis = System.currentTimeMillis();
httpCodec.writeRequestHeaders(request);
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
// If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
// Continue" response before transmitting the request body. If we don't get that, return what
// we did get (such as a 4xx response) without ever transmitting the request body.
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
responseBuilder = httpCodec.readResponseHeaders(true);
}
// Write the request body, unless an "Expect: 100-continue" expectation failed.
if (responseBuilder == null) {
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
}
httpCodec.finishRequest();
if (responseBuilder == null) {
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
pia,代碼出來了,來,扣
這里把之前兄弟們傳下來的數(shù)據(jù)都給拿了出來(都大結(jié)局了)httpCodec, streamAllocation, request
httpStream.writeRequestHeaders(request);
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
responseBuilder = httpCodec.readResponseHeaders(true);
}
if (responseBuilder == null) {
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
}
上面代碼是寫入請求頭信息跟寫入請求體信息
httpCodec.finishRequest();
這里結(jié)束請求了
if (responseBuilder == null) {
responseBuilder = httpCodec.readResponseHeaders(false);
}
接下來這里獲取響應(yīng)頭的信息
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
這里構(gòu)建了Response, 傳入原請求,握手的情況,請求的時間,接收到響應(yīng)的時間
if (forWebSocket && code == 101) {
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
這里將body修改為空響應(yīng),或者是響應(yīng)體信息
最后就是返回response給上個攔截器了。
總結(jié)一下這邊所做的內(nèi)容就是
1,獲取一些從上層的各個攔截器處理完成后傳入的對象
2,寫入請求頭信息
3,寫入請求體信息
4,結(jié)束請求
5,讀取響應(yīng)頭信息
6,讀取響應(yīng)體信息或標(biāo)記為空響應(yīng)信息
7,判斷請求頭是否有close標(biāo)記,是則斷開連接
8,如果有協(xié)議異常,拋出
9,返回響應(yīng)數(shù)據(jù)至上層攔截器
這邊做的事情,其實很多都是上一個攔截器(ConnectInterceptor )已經(jīng)準(zhǔn)備好的,也有一些數(shù)據(jù)是一路傳了下來比如httpCodec, streamAllocation, request,在這邊主要是做了一個請求的發(fā)起以及數(shù)據(jù)的響應(yīng)。
ok,最后一個官方攔截器講完了,我為啥要說“官方”呢,因為這里還有我們可以自定義的攔截器,回到我們最初的攔截器集合代碼那里
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.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());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
其中interceptors.addAll(client.interceptors())跟 interceptors.addAll(client.networkInterceptors())都是我們可以自行添加的,不同的是前后順序的區(qū)別,第一個
interceptors.addAll(client.interceptors())
是在請求發(fā)送前,以及網(wǎng)絡(luò)響應(yīng)后所執(zhí)行的攔截器,比如我們的HttpLoggingInterceptor攔截器,插入的就是這個位置
HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.BODY;
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Utils.logAll("OkHttpClient", message);
}
});
loggingInterceptor.setLevel(level);
okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJarImpl(new MemoryCookieStore()))
.addInterceptor(loggingInterceptor)
.build();
而如果插入到networkInterceptors這個位置呢,就有一定的區(qū)別,因為這是處于第六個攔截器,這時的請求已經(jīng)經(jīng)過了前面幾個攔截器的處理,比如重定向,請求跟響應(yīng)的處理等,這里可以得到更多的信息。當(dāng)然相反的,這里獲取到的響應(yīng)也是最初的(他是CallServerInterceptor的上一層),沒有經(jīng)過其他攔截器的響應(yīng)處理,是否需要這些數(shù)據(jù)就看各自的需求了。
好了,okhttp的底層原理暫時告一段落,其實里面的內(nèi)容真的很龐大,要一個一個點去深挖我覺得是很耗費(fèi)精力的,與其如此不如先把流程走透,學(xué)習(xí)他人的設(shè)計想法跟思路,這是我們提升自己代碼技巧最直觀最實際的做法。