Okhttp的请求由RealCall进行发起请求,发请求之前会调用getResponseWithInterceptorChain()方法,getResponseWithInterceptorChain()是okhttp3中的精髓设计之一。
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
}
拦截器处理流程图:
获取okhttpClient中设置的各个intercepter拦截器,通过拦截器链对请求数据和返回数据进行处理,内部采用责任链模式,将每一个拦截器对应负责的处理任务进行严格分配,最后将请求结果返回并回调到暴露给调用者的接口上。这个处理形式是一个U字形处理,跟事件分发机制处理相似。
Interceptor代码:
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// Request阶段,该拦截器在Request阶段负责做的事情
// 调用RealInterceptorChain.proceed(),其实是在递归调用下一个拦截器的intercept()方法
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
// Response阶段,完成了该拦截器在Response阶段负责做的事情,然后返回到上一层的拦截器。
return response;
}
这里先调用了 chain.request 方法获取到了本次请求的 Request 对象,
之后调用了 chain.proceed 方法递归调用下一个拦截器的 interceptor 方法。
最后返回了 chain.proceed 方法所返回的 Response。
各拦截器添加和处理顺序:
各拦截器做的内容
自定义拦截器intercepters:这是最早进行链路处理的,由用户自定义添加
retryAndFollowup:对连接不成功或者需要重定向的情况进行try-catch处理,进行重试或者交给下一层bradge。
bridgeInterceptor:主要负责设置内容长度、编码方式、设置gzip压缩、添加请求头、cookie等相关功能
CacheInterceptor:如果本地有了可⽤的Cache,就可以在没有网络交互的情况下就返回缓存结果。需要手动在OkHttpClient创建中添加缓存文件路径,大小,才能使缓存生效。只有get请求才能缓存,post请求不能缓存。
new OkHttpClient.Builder()
.cache(new Cache(new File("path"),24*1024*1024))
.build();
ConnectInterceptor:负责找到或者新建一个连接,并获取对应的socket流
networkInterceptors:这里也是开发者自己设置的,所以本质上和第一个拦截器差不多,但是由于位置不同,所以用处也不同。这个位置添加的拦截器可以看到请求和响应的数据了,所以可以做一些网络调试。
CallServerInterceptor:进行网络数据的请求和响应了,也就是实际的网络I/O操作,通过socket读写数据。
为什么要做这么多拦截器呢?是为了遵从单一职责原则,每个拦截器有各自本职工作,只做一件事。
-
应用拦截器和网络拦截器有什么区别
OkHttp的拦截器分为应用拦截器和网络拦截器。粗略地说,一个请求先经过应用拦截器,再进入内核,再进入网络拦截器。其调用关系是一个责任链,看起来很类似一个递归调用。应用拦截器只关心发起的请求和最终得到的结果(不关心重定向或者重试这样的中间响应),也可以拦截Chain.proceed()或多次调用Chain.proceed()。而网络拦截器则可以看成是网络调用模块,可以操作重定向或者重试的中间响应。同时,如果应用拦截器决定短路并以缓存返回,则网络拦截器就得不到调用。
应用拦截器可以对request和response进行修改,可以打印日志,可以添加一些headder。
网友评论