概要
我把拦截器作为作为
OkHttp
框架的首篇是因为我认为它是OkHttp
框架的精髓所在,无论我们的任何请求方式,最终都要经过一个个的拦截器,实现对网络的访问,它使用的是责任链模式,作用是在访问网络之前做一些 预前工作。
拦截链的组成
[ 1 ] 用户自定义拦截器 -
cient.interceptors()
[ 2 ] 重试并跟踪拦截器 -RetryAndFollowUpInterceptor(client)
[ 3 ] 桥接拦截器 -BridgeInterceptor(client.cookieJar())
[ 4 ] 缓存拦截器 -CacheInterceptor(client.internalCache())
[ 5 ] 连接拦截器 -ConnectInterceptor(client)
[ 6 ] 用户自定义网络拦截器 -client.networkInterceptors()
[ 7 ] 服务器调用拦截器 -CallServerInterceptor(forWebSocket)
其中 用户自定义拦截器 和 用户自定义网络拦截器 是用户自定义的,可以根据处理的业务自定义拦截器的功能。
源码剖析
外部调用入口
public class GetExample {
//声明一个OkHttpClient对象
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
//声明Request请求
Request request = new Request.Builder()
.url(url)
.build();
// [ 1 ] 调用execute()方法,进行网络请求,以此方法为入口调取拦截链
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
public static void main(String[] args) throws IOException {
GetExample example = new GetExample();
String response = example.run("https://raw.github.com/square/okhttp/master/README.md");
System.out.println(response);
}
}
[1]
client.newCall(request)
方法声明了一个RealCall
对象,而方法execute()
进入了RealCall
类中execute()
实现方法后,进而调取方法getResponseWithInterceptorChain()
fun getResponseWithInterceptorChain(): Response {
//添加完整的 拦截器链
val interceptors = ArrayList<Interceptor>()
//添加 [用户自定义] 拦截器
interceptors.addAll(cient.interceptors())
//添加重试并跟踪拦截器
interceptors.add(RetryAndFollowUpInterceptor(client))
//添加桥接拦截器
interceptors.add(BridgeInterceptor(client.cookieJar()))
//添加缓存拦截器
interceptors.add(CacheInterceptor(client.internalCache()))
//添加连接拦截器
interceptors.add(ConnectInterceptor(client))
if (!forWebSocket) {
//添加 [用户自定义] 网络拦截器
interceptors.addAll(client.networkInterceptors())
}
//添加最后一个服务器调用拦截器
interceptors.add(CallServerInterceptor(forWebSocket))
//获取从拦截器链中 获取 第0个位置的拦截器包装成 RealInterceptorChain类型
val chain = RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis())
var calledNoMoreExchanges = false
try {
//[ 2 ]调取开始执行的方法
val response = chain.proceed(originalRequest)
if (transmitter.isCanceled) {
closeQuietly(response)
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw transmitter.noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null)
}
}
}
[ 2 ] 组织添加完所有的拦截器后,获取
拦截链
中第一个拦截器,调用
chain.proceed(originalRequest)`方法,进行执行
fun proceed(request: Request, transmitter: Transmitter, exchange: Exchange?): Response {
//判定当前 index是否 大于 拦截链的总数
if (index >= interceptors.size) throw AssertionError()
calls++ //调取次数
//如果我们已经有一个流,请确认传入的请求将使用它
if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
throw IllegalStateException("network interceptor " + interceptors[index - 1] +
" must retain the same host and port")
}
//如果我们已经有了一个流,请确认这是对chain.proceed()的唯一调用
if (this.exchange != null && calls > 1) {
throw IllegalStateException("network interceptor " + interceptors[index - 1] +
" must call proceed() exactly once")
}
// 获取链中的下一个拦截器的实例,封装成 RealInterceptorChain
val next = RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
//获取当前的拦截器
val interceptor = interceptors[index]
@Suppress("USELESS_ELVIS")
// [3] 执行当前拦截器的 intercept函数,并将下一个拦截器实例作为参数传入
val response = interceptor.intercept(next) ?: throw NullPointerException(
"interceptor $interceptor returned null")
//确认下一个拦截器调用了chain.proceed()
if (exchange != null && index + 1 < interceptors.size && next.calls != 1) {
throw IllegalStateException("network interceptor " + interceptor +
" must call proceed() exactly once")
}
if (response.body() == null) {
throw IllegalStateException(
"interceptor $interceptor returned a response with no body")
}
//返回最终的Response实例
return response
}
[ 3 ] 执行当前拦截器的
intercept
函数,并将下一个拦截器实例作为参数传入方法interceptor.intercept(next)
提示
拦截链中的一个拦截器是 用户自定义的,若用户不进行第一,则第二拦截器将处于第一位置,即
RetryAndFollowUpInterceptor
拦截器,我们假设用户未进行自定义,则当前将进入RetryAndFollowUpInterceptor.kt
,执行方法interceptor.intercept(next)
public final class RetryAndFollowUpInterceptor implements Interceptor {
private static final int MAX_FOLLOW_UPS = 20;
private final OkHttpClient client;
public RetryAndFollowUpInterceptor(OkHttpClient client) {
this.client = client;
}
@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) {
//准备创建一个携带{@code request}的流。如果存在连接,这更喜欢使用现有的 。
transmitter.prepareToConnect(request);
if (transmitter.isCanceled()) {
throw new IOException("Canceled");
}
Response response;
boolean success = false;
try {
//下一个拦截器调取proceed函数,进行执行
//@重要 每一个拦截在完成自己所需处理的业务后,都回调取 @方法[ realChain.proceed(request, transmitter, null);]
//然后在外部会传入 拦截链中的下一个拦截器实例,从而实现责任链模式,完成每一个链既定业务,最后返回数据会逐次 [向上返]
response = realChain.proceed(request, transmitter, null);
success = true;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), transmitter, false, request)) {
throw e.getFirstConnectException();
}
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, transmitter, requestSendStarted, request)) throw e;
continue;
} finally {
// 抛出一个网络调用异常,释放所有资源.
if (!success) {
transmitter.exchangeDoneDueToException();
}
}
//以下处理皆要等待所有的拦截器执行完毕,逐次[向上]返
...
priorResponse = response;
}
}
[4] 下一个拦截器调取proceed函数,进行执行;每个[拦截器]完成既定的业务都会调取下一个拦截器,最后调取
CallServerInterceptor.kt
的方法interceptor.intercept(next)
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val exchange = realChain.exchange()
//获取请求实例
val request = realChain.request()
//获取请求体
val requestBody = request.body()
...
//@重点 做判定,若当前请求方法不是 GET或 HEAD 并且 请求体不为 Null 则判定成立
if (HttpMethod.permitsRequestBody(request.method()) && requestBody != null) {
//如果请求上有一个“Expect: 100-continue”报头,则等待一个“HTTP/1.1 100”报头
//在发送请求体之前继续“响应”。如果我们没有收到,返回
//在没有传输请求体的情况下,我们确实得到了(例如4xx响应)
//在[预用知识说明]标签 ==> { “Expect: 100-continue”的来龙去脉 } 中做详细说明
if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
exchange.flushRequest()
responseHeadersStarted = true
//开始调用响应头
exchange.responseHeadersStart()
// 读取响应头
responseBuilder = exchange.readResponseHeaders(true)
}
if (responseBuilder == null) {
if (requestBody.isDuplex()) {
// 准备一个双重主体,以便应用程序稍后可以发送请求主体。
exchange.flushRequest()
//创建一个buffer
val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
//请求体写入buff中
requestBody.writeTo(bufferedRequestBody)
} else {
// 如果满足“Expect: 100-continue”期望,则编写请求主体
val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
requestBody.writeTo(bufferedRequestBody)
bufferedRequestBody.close()
}
} else {
exchange.noRequestBody()
if (!exchange.connection().isMultiplexed) {
//如果没有满足“Expect: 100-continue”期望,请阻止HTTP/1连接
//避免重复使用。否则,我们仍然有义务将请求体传输到
//让连接保持一致的状态。
exchange.noNewExchangesOnConnection()
}
}
} else {
//没有请求体
exchange.noRequestBody()
}
if (requestBody == null || !requestBody.isDuplex()) {
//将所有缓冲数据写入底层接收器(如果存在的话)。然后这个sink是递归不断刷新
//将数据尽可能地推送到最终目的地。通常, 目标是一个网络套接字或文件。
exchange.finishRequest()
}
if (!responseHeadersStarted) {
//仅在接收响应头之前调用。
// 连接是隐式的,通常与最后一个[connectionAcquired]事件相关。
//这可以被调用超过1次为一个[Call]。
exchange.responseHeadersStart()
}
if (responseBuilder == null) {
//从HTTP传输解析响应头的字节。
responseBuilder = exchange.readResponseHeaders(false)!!
}
//一个HTTP响应。
//该类的实例不是不可变的:响应体是一次性的
//只使用一次,然后关闭的值。所有其他属性都是不可变的。
var response = responseBuilder
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
var code = response.code() //获取响应 Code
if (code == 100) {
// 服务器发送了100-continue,即使我们没有请求。
//再读一遍实际的响应
response = exchange.readResponseHeaders(false)!!
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
code = response.code()
}
//在接收响应标头后立即调用
exchange.responseHeadersEnd(response)
response = if (forWebSocket && code == 101) {
//连接叠积,但我们需要确保拦截器看到非空响应体。
response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build()
} else {
response.newBuilder()
.body(exchange.openResponseBody(response))
.build()
}
//关闭连接
if ("close".equals(response.request().header("Connection"), ignoreCase = true) ||
"close".equals(response.header("Connection"), ignoreCase = true)) {
exchange.noNewExchangesOnConnection()
}
//抛出连接异常
if ((code == 204 || code == 205) && response.body()?.contentLength() ?: -1 > 0) {
throw ProtocolException(
"HTTP $code had non-zero Content-Length: ${response.body()?.contentLength()}")
}
//返回响应数据
return response
}
重要
每一个拦截在完成自己所需处理的业务后,都回调取方法
realChain.proceed(request, transmitter, null);
然后在外部会传入 拦截链中的下一个拦截器实例,从而实现责任链模式,完成每一个链既定业务,进入下一个链的调用,最后会在CallServerInterceptor.kt
的方法interceptor.intercept(next)
向服务器请求数据,最后返回数据会逐次 向上返,然后进行下半部分的业务处理,最后将获取的Response
对象返回至前台