CallServerInterceptor拦截器的代码量也不大,但是他的核心方法Response intercept(Chain chain)就占据了三分之二的量,所有的核心代码都在这个方法里面。
他有两个作用,一是向服务器发起真正的网络请求;二是接收服务器返回的响应数据。
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
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);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(true);
}
if (responseBuilder == null) {
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()) {
streamAllocation.noNewStreams();
}
}
httpCodec.finishRequest();
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder.request(request).handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build();
int code = response.code();
if (code == 100) {
responseBuilder = httpCodec.readResponseHeaders(false);
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) {
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;
}
代码第一行创建一个拦截器的链:RealInterceptorChain,我们所有的拦截器的链都是都是通过这个链然后调用realChain.proceed()将这些链连接起来。
第二行至第六行创建的对象HttpCodec、StreamAllocation、RealConnection、RealConnection、RealConnection、sentRequestMillis,我们都不陌生。
然后是httpCodec.writeRequestHeaders(request)这行代码,他的作用是向httpCodec写入请求信息request(包括请求头)。
接下来是request.body().writeTo(bufferedRequestBody),它的作用是向请求体里面写入我们的请求信息,之后调用的方法httpCodec.finishRequest()标志着我们发起网络请求完成,然后接下来的工作是读取请求到的数据:
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
这里主要是读取完成网络请求得到响应后响应体里面的信息。
首先是获取到Response对象:
Response response = responseBuilder.request(request).handshake(streamAllocation.connection().handshake().sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build();
紧接着的if (code == 100) {}和if (forWebSocket && code == 101) {}两个判断都是将Response对象处理成我们需要的格式。
倒数第二个if判断中,满足指定条件的话,就会对这个请求的连接进行处理:禁止在主机上重新创建这个流连接,关闭Response里面的流和Connection连接。
最后一个if判断,当请求返回码为204或者205且response有内容的时候,直接抛出异常。最后返回请求到的信息response。
总结:
1、 创请求需要的参数对象;
2、调用httpCodec.writeRequestHeaders(request)向httpCodec写入请求信息(包括请求头);
3、向请求体的body中写入我们的请求信息(request.body().writeTo(bufferedRequestBody));
4、httpCodec.finishRequest()的调用标志着我们发起网络请求完成,然后接下来的工作是读取请求到的数据;
5、调用responseBuilder = httpCodec.readResponseHeaders(false)读取请求响应的头部信息;
6、然后通过多个条件判断,将我们获取到的response对象处理成我们能够使用的格式。
回顾——OKHttp完成一次请求的大致过程:
1、创建一个Call对象并封装请求信息;
2、通过Dispatcher对请求进行分发;
3、然后调用getResponseWithInterceptors()方法,在多层次的拦截器链中完成请求并返回response数据。多层次拦截器包括:
——RetryAndFollowUpInterceptor:重试和请求失败后重定向拦截器。主要作用是:初始化拦截器数据的工作,创建StreamAllocation对象。
——BridgeInterceptor:桥接和适配拦截器;补充用户创建使用过程中缺少的OKHttp请求头。
——CacheInterceptor:缓存拦截器,处理缓存的一些功能。
——ConnectInterceptor:连接池拦截器,他是CallServerInterceptor拦截器的基础。主要负责创建和回收可用的网络连接,回收遵循GC机制。
——CallServerInterceptor:主要负责将网络请求写进网络IO流中,并从网络IO流中读取服务端返回给我们的数据(发送请求,读取响应)。