OKHttp系列十二、CallServerInterceptor服务请求拦截器

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流中读取服务端返回给我们的数据(发送请求,读取响应)。
原创文章 118 获赞 149 访问量 9万+

猜你喜欢

转载自blog.csdn.net/haoyuegongzi/article/details/103518037
今日推荐