承接上文
我们在在OkHttp源码分析(一)中分析过getResponseWithInterceptorChain()方法源码,其中设置了各种截获器,总结起来如下图所示:
源码分析
我们再来看一看getResponseWithInterceptorChain()方法的源码,观察截获器的相关操作
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
//所有的截获器最终构建了一个chain
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//最终执行proceed方法
return chain.proceed(originalRequest);
}
所有现在重要的是RealInterceptorChain#proceed方法,我们接着看
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
.........
// 判断每一个截获器都有对应的处理,没有则创建RealInterceptorChain,即是创建当前的类,不断的迭代
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
//并执行当前的截获器的intercept方法
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
.........
return response;
}
现在终于到执行到截获器中的intercept方法了,接下来会简要分析一下
RetryAndFollowUpInterceptor:失败重试及重定向时使用
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
//实例化流分配,其实就是一个Socket管理类,管理着Connections、Streams、Calls三者之间的关系,
//其中有我们所说的Socket自动选择最佳路径,拥有自动维护的连接池,减少握手次数
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
int followUpCount = 0;
Response priorResponse = null;
while (true) {
//死循环,判断当前请求是否取消,若取消则释放连接
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
//又调用proceed方法,推进链中下一个节点
response = realChain.proceed(request, streamAllocation, null, null);
//若无异常则不用释放连接,后续判断
releaseConnection = false;
} catch (RouteException e) {
//捕获到路由寻址异常,尝试恢复连接,若是还是没能连接成功,抛出异常
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getLastConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
//连接关闭异常,说明请求没有被发送,否则请求已发出
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
//综合以上结果,判断是否关闭连接
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
//重定项,根据response重建request
Request followUp = followUpRequest(response, streamAllocation.route());
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
//如果不是重定向,返回response
return response;
}
.........
if (++followUpCount > MAX_FOLLOW_UPS) {
//有最大次数限制20次
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
...........
//把重定向的请求赋值给request,以便再次进入循环执行
//重定向功能默认是开启的,可以选择关闭,然后去实现自己的重定向功能:
request = followUp;
priorResponse = response;
}
}
BridgeInterceptor:负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应
其实说白了BridgeInterceptor就是在request阶段对请求头添加一些字段,在response阶段对响应进行一些GZIP解压操作。GZIP是使用非常普遍的数据压缩格式,或者说是一种文件格式,HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术,通常使用GZIP压缩技术压缩网页的内容,传输之后经过解压显示出来.这样主观的体现就是加载速度很快
@Override
public Response intercept(Chain chain) throws IOException {
/** 获取当前的请求*/
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
/**注意,这是获得的请求是最原始的请求,没有请求头header,所以BridgeInterceptor截获器就是起这个作用*/
RequestBody body = userRequest.body();
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
/**添加Content-Length、Transfer-Encoding、Host、Connection、Accept-Encoding、Range、Cookie、User-Agent*/
.........
/** 获取网络响应,转换为用户友好的响应 */
Response networkResponse = chain.proceed(requestBuilder.build());
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
/** GZIP解压 */
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
return responseBuilder.build();
}
CacheInterceptor:负责读取缓存直接返回、更新缓存 详见HTTP缓存机制及原理
@Override
public Response intercept(Chain chain) throws IOException {
//读取候选缓存,从缓存中获得Response,但是不一定存在
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
//创建缓存策略(强制缓存,对比缓存等策略);
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
//缓存监测
if (cache != null) {
cache.trackResponse(strategy);
}
//候选缓存无效就关闭它
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body());
}
// 根据策略,禁用网络,并且缓存无效,则直接报错
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
// 根据策略,不使用网络,则读取缓存返回响应
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
//若是前面两个都没有返回,则执行下一个拦截器
networkResponse = chain.proceed(networkRequest);
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// 接收到的网络结果,如果是code 304, 使用缓存,返回缓存结果(对比缓存)
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
cache.trackConditionalCacheHit();
cache.update(cacheResponse, response);
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
//读取网络结果
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
// 将响应response进行缓存
if (cache != null) {
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}
CallServerInterceptor:负责和服务器建立连接
建立连接实际上就是创建了一个 HttpCodec 对象
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
//StreamAllocation 上述过程中提到过是Socket管理类,这里只分析截获器,就不在向深处挖掘
StreamAllocation streamAllocation = realChain.streamAllocation();
boolean doExtensiveHealthChecks = !request.method().equals("GET");
//获取realConnetion
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
//执行下一个拦截器
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
CallServerInterceptor:负责向服务器发送请求数据、从服务器读取响应数据
/**
主干内容:
1、向服务器发送 request header
2、如果有 request body,就向服务器发送
3、读取 response header,先构造一个 Response 对象
4、如果有 response body,就在 3 的基础上加上 body 构造一个新的 Response 对象
*/
@Override
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());
/** 1、向服务器发送 request header*/
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
/** 2、如果有 request body,就向服务器发送*/
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
/**询问Server是否愿意接受数据*/
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
/**构建responseBuilder对象*/
responseBuilder = httpCodec.readResponseHeaders(true);
}
//如果服务器允许发送请求body发送
if (responseBuilder == null) {
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
} else if (!connection.isMultiplexed()) {
//省略部分代码
}
//结束请求
httpCodec.finishRequest();
//构建请求buidder对象
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
//3、读取 response header,先构造一个 Response 对象
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
..........
//4、如果有 response body,就在 3 的基础上加上 body 构造一个新的 Response 对象
if (forWebSocket && code == 101) {
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
.........
return response;
}