OkHttp网络请求框架源码解析二
本篇讲解OkHttp核心知识拦截器,共有5个拦截器,分别为RetryAndFollowUpInterceptor,BridgeInterceptor, CacheInterceptor,ConnectInterceptor 和 CallServerInterceptor。下面一一讲到。
//上一篇讲到,作为Runnable的 AsyncCall,最终的execute()方法为RealCall里面的execute()方法。
@Override protected void execute() {
//获取响应回来的数据response
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
//回调onFailure
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
//回调onResponse
responseCallback.onResponse(RealCall.this, response);
}
......
//线程池执行完线程任务后,调用此方法.
client.dispatcher().finished(this);
}
//不管是同步请求,还是异步请求,都是通过getResponseWithInterceptorChain方法获取响应。
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
//添加用户自定义的拦截器
interceptors.addAll(client.interceptors());
......
//创建拦截器链
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
//创建下一个拦截器链
return chain.proceed(originalRequest);
}
//chain.proceed()方法实现
public Response proceed() throws IOException {
......
//创建下一个拦截器链 index+1
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
return response;
}
第一个拦截器,重试重定向拦截器:RetryAndFollowUpInterceptor。
1.创建StreamAllocation对象;
2.调用RealInterceptorChain.proceed()方法进行网络请求;
3.根据结果判断是否重新请求;
4.调用下一个拦截器;
//RetryAndFollowUpInterceptor拦截器里面的核心方法intercept(),
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//StreamAllocation 获取建立Http连接的所有网络组件
//虽然在这里被创建,但是这里没有使用。
streamAllocation = new StreamAllocation(
client.connectionPool(), createAddress(request.url()), callStackTrace);
......
//重试次数20次
if (++followUpCount > 20) {
streamAllocation.release();
}
}
第二个拦截器,桥接拦截器,BridgeInterceptor。
1.将request请求转换成可以进行网络访问的请求;
2.进行网络请求;
3.将响应response转换成客户度可以用的response。
//BridgeInterceptor桥接拦截器的核心方法intercept()
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
给Request添加各种头部信息
requestBuilder.header("Content-Type", contentType.toString());
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
}
}
......
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
requestBuilder.header("Connection", "Keep-Alive");
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
requestBuilder.header("Cookie", cookieHeader(cookies));
requestBuilder.header("User-Agent", Version.userAgent());
//从服务器获取response
Response networkResponse = chain.proceed(requestBuilder.build());
//将服务器返回的数据头部转换成客户端可以接收的形式
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(),
networkResponse.headers());
第三个拦截器,缓存拦截器CacheInterceptor。
//CacheInterceptor核心方法intercept
@Override public Response intercept(Chain chain) throws IOException {
//获取缓存
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
//创建CacheStrategy
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(),
cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
//关于缓存命中率,如果使用了缓存,则hitCount++。
cache.trackResponse(strategy);
//第一种情况,如果不能使用网络,并且没有缓存,则OkHttp内部构建一个504响应作为response。
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();
}
//第二种情况,不能使用网络,但是有缓存,则使用缓存作为response。
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
//第三种情况,可以使用网络,不管是否有缓存都会调用chain.proceed方法进行网络请求。
Response networkResponse = null;
networkResponse = chain.proceed(networkRequest);
//如果有缓存,并且服务器响应码为304,表示内容未被修改,则使用缓存作为response.
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();
return response;
}
}
//如果没有缓存,则将刚才网络请求的response作为response.
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
//如果代码能走到这里,说明前面网络请求的响应码不是304,表示response被修改了,则更新缓存。
if (cache != null) {
//条件判断
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
//存入新的缓存
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
//假如请求方式不是get,则删除缓存,因为OkHttp只对get方式的请求进行缓存。
if (HttpMethod.invalidatesCache(networkRequest.method())) {
cache.remove(networkRequest);
}
}
return response;
}
第四个拦截器,连接池拦截器,ConnectInterceptor。
//ConnectInterceptor整个类的代码
public final class ConnectInterceptor implements Interceptor {
public final OkHttpClient client;
public ConnectInterceptor(OkHttpClient client) {
this.client = client;
}
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
//StreamAllocation用来获取网络请求需要的所有组件
StreamAllocation streamAllocation = realChain.streamAllocation();
boolean doExtensiveHealthChecks = !request.method().equals("GET");
//HttpCodec用来 编码request,解码response
HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);
//RealConnection 进行实际的网络io传输
RealConnection connection = streamAllocation.connection();
//将重要的HttpCodec对象和RealConnection对象传递给后面的拦截器
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
}
//streamAllocation.newStream方法的实现
public HttpCodec newStream(OkHttpClient client, boolean doExtensiveHealthChecks) {
//通过findHealthyConnection方法获取RealConnection
RealConnection resultConnection = findHealthyConnection(connectTimeout,
readTimeout,writeTimeout,connectionRetryEnabled, doExtensiveHealthChecks);
//通过RealConnection的newCodec方法获取HttpCodec对象,最后返回。
HttpCodec resultCodec = resultConnection.newCodec(client, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
}
//findHealthyConnection方法的实现
private RealConnection findHealthyConnection(){
while (true) {
//循环里面,通过findConnection()方法获取RealConnection对象。然后返回。
RealConnection candidate = findConnection(connectTimeout, readTimeout,
writeTimeout,
connectionRetryEnabled);
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
......
}
//findConnection()方法的实现
private RealConnection findConnection(){
//先复用已有的连接,如果满足条件,则返回
RealConnection allocatedConnection = this.connection;
if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
return allocatedConnection;
}
//如果不能复用,则从连接池connectionPool里面获取RealConnection对象。
Internal.instance.get(connectionPool, address, this, null);
if (connection != null) {
return connection;
}
//调用RealConnection对象的connect()方法进行实际的网络请求连接
result.connect(connectTimeout, readTimeout, writeTimeout,
connectionRetryEnabled);
//然后把上面的连接放入连接池connectionPool
Internal.instance.put(connectionPool, result);
}
第五个拦截器,CallServerInterceptor。
//CallInterceptor拦截器的核心方法实现
@Override public Response intercept(Chain chain) throws IOException {
//5个重要的对象,第一个:拦截器链
RealInterceptorChain realChain = (RealInterceptorChain) chain;
//5个重要的对象,第二个:HttpCodec编码request,解码response
HttpCodec httpCodec = realChain.httpStream();
//5个重要的对象,第三个:分配网络请求组件
StreamAllocation streamAllocation = realChain.streamAllocation();
//5个重要的对象,第四个:真正的网络请求
RealConnection connection = (RealConnection) realChain.connection();
//5个重要的对象,第五个:
Request request = realChain.request();
//第一步:写请求头。
httpCodec.writeRequestHeaders(request);
//第二步:写请求体
request.body().writeTo(bufferedRequestBody);
//第三步:结束请求
httpCodec.finishRequest();
//第四步:读取response请求头
responseBuilder = httpCodec.readResponseHeaders(false);
//第五步:读取response请求体
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}