关键代码:
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
//①获取拦截器链中的HttpCodec、StreamAllocation、RealConnection对象
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
realChain.eventListener().requestHeadersStart(realChain.call());
//②调用httpCodec.writeRequestHeaders(request)将请求头写入缓存
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
//③判断是否有请求体,如果有,请求头通过携带特殊字段 Expect:100-continue来询问服务器是否愿意接受请求体。(一般用于上传大容量请求体或者需要验证)
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
//调用真正发送给服务器
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
//服务端返回100,表示愿意接受请求体responseBuilder为null(见下面Http2Codec的readResponseHeaders方法)
responseBuilder = httpCodec.readResponseHeaders(true);
}
if (responseBuilder == null) {
//服务器愿意会响应100(responseBuilder 即为nul)。这时候才能够继续发送剩余请求数据。
realChain.eventListener().requestBodyStart(realChain.call());
long contentLength = request.body().contentLength();
CountingSink requestBodyOut =
new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
//写入请求体
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
realChain.eventListener()
.requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
} else if (!connection.isMultiplexed()) {
//服务器不愿意接受请求体,调用noNewStreams关闭相关socket
streamAllocation.noNewStreams();
}
}
//④结束请求
httpCodec.finishRequest();
/**代码走到这里的responseBuilder情况为:
* 1.post请求,请求头包含Expect,服务端允许接受请求体,并且已经发出了请求体,responseBuilder为null
* 2.post请求,请求头包含Expect,服务端不允许接受请求体,responseBuilder不为null
* 3.post请求,没有请求体,responseBuilder为null
* 4.get请求,responseBuilder为null
*/
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
//根据服务器返回的数据构建 responseBuilder对象 (传入的expectContinue为false,不会return null)
responseBuilder = httpCodec.readResponseHeaders(false);
}
//⑤构建Response对象
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
//第一次查询服务器是否支持接受请求体的,而不是真正的请求对应的结果响应。所以接着:
int code = response.code();
if (code == 100) {
//如果响应了100,这代表了请求Expect: 100-continue成功响应,需要马上再次读取一份响应头,这才是真正的请求对应的响应头。
responseBuilder = httpCodec.readResponseHeaders(false);
//⑤构建Response对象
response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
realChain.eventListener()
.responseHeadersEnd(realChain.call(), response);
if (forWebSocket && code == 101) {
//WebSocket请求
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
//读取响应体数据
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
//客户端或者服务端不希望长连接,那么就关闭socket
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
//如果服务器返回204/205(表示没有响应体),但是解析Content-Lenght>0(表示响应体字节长度),出现冲突,抛出协议异常
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
//⑥返回response
return response;
}
Http2Codec.java(写数据和读取数据)
private Http2Stream stream;
@Override public void writeRequestHeaders(Request request) throws IOException {
if (stream != null) return;
boolean hasRequestBody = request.body() != null;
List<Header> requestHeaders = http2HeadersList(request);
stream = connection.newStream(requestHeaders, hasRequestBody);
stream.readTimeout().timeout(chain.readTimeoutMillis(), TimeUnit.MILLISECONDS);
stream.writeTimeout().timeout(chain.writeTimeoutMillis(), TimeUnit.MILLISECONDS);
}
@Override public Response.Builder readResponseHeaders(boolean expectContinue) throws IOException {
List<Header> headers = stream.takeResponseHeaders();
Response.Builder responseBuilder = readHttp2HeadersList(headers);
if (expectContinue && Internal.instance.code(responseBuilder) == HTTP_CONTINUE) {
//注意传过来的expectContinue
//服务端返回100,表示愿意接受请求体 responseBuilder为null
return null;
}
return responseBuilder;
}
大致流程
- 获取拦截器链中的HttpCodec、StreamAllocation、RealConnection对象
- 调用httpCodec.writeRequestHeaders(request)将请求头写入缓存
- 判断是否有请求体,如果有,请求头通过携带特殊字段 Expect:100-continue来询问服务器是否愿意接受请求体。(一般用于上传大容量请求体或者需要验证)
- 通过httpCodec.finishRequest()结束请求
- 通过responseBuilder构建Response
- 返回Response
总结:CallServerInterceptor完成HTTP协议报文的封装和解析。