该系列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;
}