目录
一、OkHttp3的拦截器
二、Interceptor接口
三、RetryAndFollowUpInterceptor
三、BridgeInterceptor
四、CacheInterceptor
五、ConnectInterceptor
六、CallServerInterceptor
七、addInterceptor与addNetworkInterceptor的区别
八、主要参考
在OkHttp3中,在执行RealCall的execute方法时,在通过HttpClient的Dispatcher执行execute方法后,将当前RealCall添加到执行/等待队列中,然后调用getResponseWithInterceptorChain()方法返回的Response;
在getResponseWithInterceptorChain()方法中,在真正执行网络请求前,会先添加上一串拦截器Interceptor,如下所示:
/** [email protected] */
/** 执行网络请求,并返回服务器响应Response */
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
// 拦截器容器
List interceptors = new ArrayList<>();
// 1.先添加用户自定义的拦截器
interceptors.addAll(client.interceptors());
// 2.重试与重定向拦截器,如重连接,对3xx系列重连接做出响应
interceptors.add(new RetryAndFollowUpInterceptor(client));
// 3.桥接拦截器,切换对用户友好的Request/Response与对服务器友好的Request/Response;
interceptors.add(new BridgeInterceptor(client.cookieJar()));
// 4.缓存拦截器,用来处理网络缓存;
interceptors.add(new CacheInterceptor(client.internalCache()));
// 5.IO连接拦截器,真实IO操作;
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
// 6.如果不是WebSocket长链接,添加用户自定义的网络拦截器
interceptors.addAll(client.networkInterceptors());
}
// 7.服务器连接拦截器,连接服务器;
interceptors.add(new CallServerInterceptor(forWebSocket));
// 创建拦截器链的实例
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null,0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
// 开始递归调用不同拦截器,并得到服务器返回结果
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
/** Interceptor.class interface*/
/**
* Observes, modifies, and potentially short-circuits requests going out and the corresponding
* responses coming back in. Typically interceptors add, remove, or transform headers on the
* request or response.
*/
public interface Interceptor {
/** 入参为拦截器链,返回值为Http响应Response */
Response intercept(Chain chain) throws IOException;
/** 内部接口 */
interface Chain {
Request request();
/** 发起网络请求方法 */
Response proceed(Request request) throws IOException;
/**
* Returns the connection the request will be executed on.
* This is only available in the chains of network interceptors;
* for application interceptors this is always null.
*/
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
}
}
每个Interceptor都要实现Interceptor接口;其中intercept()方法作为拦截器的拦截方法,执行具体逻辑,proceed()方法作为递归调用下一个拦截器的方法,从而保证拦截器链按顺序执行下去;
重连接与重定向拦截器:在intercept()方法中先做好网络连接前的准备,如果网络请求没有被取消掉,就开始递归调用proceed方法,获取下一层Interceptor的返回值,赋值给Response对象,在递归的过程中可能会出现异常,比如服务器返回3XX类型的重定向Reponse,则根据Response携带的信息,在followUpRequest方法中创建新的Request对象,这里命名为followUp。默认最多可重定向20次,超过20次则抛出异常;如果出现IO类连接关闭异常,则会重试;
/** intercept@RetryAndFollowUpInterceptor */
/** 拦截方法 */
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Transmitter transmitter = realChain.transmitter();
int followUpCount = 0;
Response priorResponse = null;
while (true) {
transmitter.prepareToConnect(request);
if (transmitter.isCanceled()) {
throw new IOException("Canceled");
}
Response response;
boolean success = false;
try {
// 递归调用proceed方法,获取下一层Interceptor的返回结果
response = realChain.proceed(request, transmitter, null);
success = true;
} catch (RouteException e) {
// 若不满足重定向的条件,抛出异常
if (!recover(e.getLastConnectException(), transmitter, false, request)) {
throw e.getFirstConnectException();
}
// 重试
continue;
} catch (IOException e) {
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
// 根据异常类型,如果不满足重试条件,则抛出异常
if (!recover(e, transmitter, requestSendStarted, request)) throw e;
// 重试
continue;
} finally {
if (!success) {
// 若抛出了异常,释放资源
transmitter.exchangeDoneDueToException();
}
}
// 在本次response中设置上一次的response,但将body设置为null
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Exchange exchange = Internal.instance.exchange(response);
Route route = exchange != null ? exchange.connection().route() : null;
// 获取重定向后的request
Request followUp = followUpRequest(response, route);
if (followUp == null) {
// 没有用于重定向的Request了,停止timeout计时并返回response
if (exchange != null && exchange.isDuplex()) {
transmitter.timeoutEarlyExit();
}
return response;
}
RequestBody followUpBody = followUp.body();
if (followUpBody != null && followUpBody.isOneShot()) {
return response;
}
closeQuietly(response.body());
if (transmitter.hasExchange()) {
exchange.detachWithViolence();
}
// 重定向不超过MAX_FOLLOW_UPS,默认20次,否则抛出异常
if (++followUpCount > MAX_FOLLOW_UPS) {
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
// 修改下次重定向的request
request = followUp;
// 记录上一次请求的response
priorResponse = response;
}
}
桥梁拦截器,其主要作用是对Requset与Response的Header做一次换装,分别将对用户友好的Request转换成对服务器友好的Request,将对服务器友好的Response转换成对用户友好的Response,也就是二次封装。主要封装的内容为HTTP中的Header属性,比如MediaType,ContentLength等,如果Cookie不为空,也会把Cookie封装到新的Request中;另外默认Accept-Encoding为gzip。
/** intercept@BridgeInterceptor */
/** 拦截方法 */
@Override
public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
// 将userRequest中原有的属性复制到新的requestBuilder中;
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
// 重新封装Header相关属性
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
boolean transparentGzip = false;
// 若未设置Accept-Encoding,自动设置gzip
if (userRequest.header("Accept-Encoding") == null
&& userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
// 将userRequest中的cookies设置进builder
List cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
// 递归调用proceed,得到服务器返回值
Response networkResponse = chain.proceed(requestBuilder.build());
// 对响应的header进行处理
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
// 根据服务端的响应构建新的Response,并将userRequest设置为其request
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
// 若之前设置了gzip压缩且response中也包含了gzip压缩,则进行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();
}
缓存拦截器:负责对缓存的读取与更新;根据当前时间,请求Request,缓存信息三个属性来构建缓存策略,通过缓存策略构建新的网络请求networkRequest,根据networkRequest的状态分成不同的情况处理:
若当前networkRequest为空,则代表当前请求不需要网络连接,继续通过缓存策略获取缓存响应cacheResponse,若cacheResponse为空,则代表没有缓存,直接构建访问失败的响应返回;若cacheResponse不为空,则直接返回cacheResponse;
若当前networkRequest不为空,则代表当前请求需要网络连接,通过调用chain.proceed()方法递归地去获取下一层拦截器的返回值;在后续的拦截器中会真正执行网络请求;
当获取到下一层拦截器的响应后,根据相应的策略判断是否需要缓存数据,重新封装本拦截器的响应Response;最终返回CacheInterceptor的Response;
/** intercept@CacheInterceptor */
/** 拦截方法 */
@Override
public Response intercept(Chain chain) throws IOException {
// 尝试获取缓存的cache
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
// 构建缓存策略
CacheStrategy strategy = new CacheStrategy.Factory(now,
chain.request(),
cacheCandidate)
.get();
// 通过缓存策略获取新的request
Request networkRequest = strategy.networkRequest;
// 通过缓存策略获取缓存中取出的response
Response cacheResponse = strategy.cacheResponse;
if (cache != null) {
cache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body());
}
// 若无需网络请求,并且没有缓存,构建一个请求失败的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();
}
// 若无需网络请求,则直接返回
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
// 需要网络请求,递归调用proceed方法获取下一个拦截器的response
networkResponse = chain.proceed(networkRequest);
} finally {
// 如果出现IO或者其他crash,回收缓存body的资源
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// 如果缓存不为空,且返回状态码为304,则整合Header属性并返回,并更新缓存中的内容
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) { // 304
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 response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
// 缓存相应的请求Request与响应的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;
}
连接拦截器:实现与服务器的连接,在内部的intercept方法中对GET方法做特殊处理,从而更新Exchange这个真正执行IO操作的实现类。
/** intercept@ConnectInterceptor */
/** 拦截方法 */
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
Transmitter transmitter = realChain.transmitter();
// We need the network to satisfy this request.
// Possibly for validating a conditional GET.
// 对GET请求做一些特殊处理
boolean doExtensiveHealthChecks = !request.method().equals("GET");
Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);
// 实际IO操作在exchange的connection方法中调用ExchangeCodeC.connection()进行
return realChain.proceed(request, transmitter, exchange);
}
连接服务拦截器:负责发起实际网络请求,将请求写入缓冲区,读取服务器的响应,然后封装响应,返回上一层拦截器;
/** 拦截器链的最后一个拦截器,发起实际网络请求,读取服务器响应 */
/** intercept@CallServerInterceptor */
/** 拦截方法 */
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Exchange exchange = realChain.exchange();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
// 更新Http引擎的sentRequestMillis属性
exchange.writeRequestHeaders(request);
boolean responseHeadersStarted = false;
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
// 如果需要服务器响应“100-continue”,根据响应做出相应处理
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
exchange.flushRequest();
responseHeadersStarted = true;
exchange.responseHeadersStart();
responseBuilder = exchange.readResponseHeaders(true);
}
if (responseBuilder == null) {
if (request.body().isDuplex()) {
// Prepare a duplex body so that the application can send a request body later.
exchange.flushRequest();
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, true));
request.body().writeTo(bufferedRequestBody);
} else {
// 如果服务器响应“100-continue”,则调用Okio将请求实体写入缓冲区
// Write the request body if the "Expect: 100-continue" expectation was met.
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, false));
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
} else {
exchange.noRequestBody();
if (!exchange.connection().isMultiplexed()) {
// 如果服务器没有响应“100-continue”,则不再写入缓冲区,避免http1请求重用;
exchange.noNewExchangesOnConnection();
}
}
} else {
exchange.noRequestBody();
}
if (request.body() == null || !request.body().isDuplex()) {
exchange.finishRequest();
}
if (!responseHeadersStarted) {
exchange.responseHeadersStart();
}
if (responseBuilder == null) {
// 读取服务器响应缓存
responseBuilder = exchange.readResponseHeaders(false);
}
// 组装Response
Response response = responseBuilder
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (code == 100) {
// 即使没发送请求服务器也响应“100-continue”,就重新读取一次真实Response
response = exchange.readResponseHeaders(false)
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
// response的Header部分封装完成
exchange.responseHeadersEnd(response);
if (forWebSocket && code == 101) {
// 连接正在升级,须保证拦截器获取到非空response.body
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
// response的Body部分封装完成
response = response.newBuilder()
.body(exchange.openResponseBody(response))
.build();
}
// 判断是否需要断开连接
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
exchange.noNewExchangesOnConnection();
}
// 对204,205状态时content-length大于零抛出异常
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
addInterceptor应用拦截器,其加入时机是在RetryAndFollowUpInterceptor之前,,有如下特点:
addNetworkInterceptor,顾名思义,网络拦截器,是在ConnectInterceptor之后,CallServerInterceptor之前,同时还要判断是否是websocket连接,主要作用:
参考链接(1):https://github.com/square/okhttp
参考链接(2):https://blog.csdn.net/qq_21556263/article/details/98847306
参考链接(3):https://github.com/AndroidPreView/AndroidNote/wiki/Okhttp-%E7%9A%84addInterceptor-%E5%92%8C-addNetworkInterceptor-%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9F