該系列OkHttp源碼分析基於OkHttp3.14.0版本
概述
用於向服務器寫數據以及從服務器讀取數據。
整個攔截器的主要邏輯是這樣的,首先向服務器發送請求頭,如果有請求體的話就向服務器發送請求體,然後就開始讀取服務器的返回。同樣的,首先讀取服務器返回的響應頭,然後根據狀態碼以及是否是websocket
協議判斷是繼續讀取響應頭還是開始讀取響應體。最後按照責任鏈,向上返回響應。
而且根據源碼可以看到,所有與服務器的讀寫操作都是由Exchange
進行的,而根據上面連接攔截器ConnectInterceptor
所提及的,Exchange
中實際與服務器進行IO交互的是ExchangeCodec
,而ExchangeCodec
中封裝了Okio的IO操作。
源碼分析
發送請求
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Exchange exchange = realChain.exchange();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
exchange.writeRequestHeaders(request);//發送請求頭
boolean responseHeadersStarted = false;
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.
// 如果請求上有一個“Expect: 100-continue”標頭,則在發送請求正文之前,等待“ HTTP / 1.1 100繼續”響應。
// 如果沒有得到,請返回我們得到的結果(例如4xx響應),而無需傳輸請求主體。
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
exchange.flushRequest();
responseHeadersStarted = true;
exchange.responseHeadersStart();
responseBuilder = exchange.readResponseHeaders(true);
}
if (responseBuilder == null) {//這裏判斷的是是否有請求頭返回
// 下面開始發送請求體
if (request.body().isDuplex()) {
// Prepare a duplex body so that the application can send a request body later.
// 準備一個雙工主體,以便應用程序以後可以發送請求主體。
exchange.flushRequest();
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, true));
request.body().writeTo(bufferedRequestBody);
} else {
// Write the request body if the "Expect: 100-continue" expectation was met.
// 如果滿足“Expect: 100-continue”的期望,寫請求體。
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, false));
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
} else {
exchange.noRequestBody();
if (!exchange.connection().isMultiplexed()) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
// from being reused. Otherwise we're still obligated to transmit the request body to
// leave the connection in a consistent state.
// 如果未達到“Expect: 100-continue”的期望,請防止HTTP / 1連接被重用。
// 否則,我們仍然有義務傳輸請求主體,以使連接保持一致狀態。
exchange.noNewExchangesOnConnection();
}
}
} else {
exchange.noRequestBody();
}
if (request.body() == null || !request.body().isDuplex()) {
exchange.finishRequest();
}
...省略部分代碼
}
整個代碼邏輯就如之前所說的,首先調用exchange.writeRequestHeaders()
發送請求頭,然後調用request.body().writeTo(bufferedRequestBody)
發送請求體。這裏有點特殊,發送請求體並不是由ExchangeCodec
進行的,而是由BufferedSink
進行的。至於爲啥要這麼做,emm,我也很好奇。
讀取響應
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Exchange exchange = realChain.exchange();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
exchange.writeRequestHeaders(request);//發送請求頭
boolean responseHeadersStarted = false;
Response.Builder responseBuilder = null;
...省略部分代碼
if (!responseHeadersStarted) {
exchange.responseHeadersStart();
}
if (responseBuilder == null) {
//獲得返回頭
responseBuilder = exchange.readResponseHeaders(false);
}
//構建響應返回
Response response = responseBuilder
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (code == 100) {//100表示需要繼續想服務端發送數據
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
// 即使我們沒有請求,服務器仍發送了100-continue。 再次嘗試讀取返回
response = exchange.readResponseHeaders(false)
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
exchange.responseHeadersEnd(response);
if (forWebSocket && code == 101) {//判斷是否是websocket或者服務端返回要求切換協議
// 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(exchange.openResponseBody(response))//這裏去拿到返回體
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
exchange.noNewExchangesOnConnection();//結束請求
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
//這裏應該屬於服務端的錯誤,204和205表示沒有返回體,但是這裏卻發現有返回體
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}