手把手讲解 OkHttp硬核知识点(2)
前言
手把手讲解系列文章,是我写给各位看官,也是写给我自己的。
文章可能过分详细,但是这是为了帮助到尽量多的人,毕竟工作5,6年,不能老吸血,也到了回馈开源的时候.
这个系列的文章:
1、用通俗易懂的讲解方式,讲解一门技术的实用价值
2、详细书写源码的追踪,源码截图,绘制类的结构图,尽量详细地解释原理的探索过程
3、提供Github 的 可运行的Demo工程,但是我所提供代码,更多是提供思路,抛砖引玉,请酌情cv
4、集合整理原理探索过程中的一些坑,或者demo的运行过程中的注意事项
5、用gif图,最直观地展示demo运行效果如果觉得细节太细,直接跳过看结论即可。
本人能力有限,如若发现描述不当之处,欢迎留言批评指正。
学到老活到老,路漫漫其修远兮。与众君共勉 !
引子
OkHttp 知名第三方网络框架SDK,使用简单,性能优秀,但是内核并不简单,此系列文章,专挑硬核知识点详细讲解.
何为硬核,就是要想深入研究,你绝对绕不过去的知识点
本文接上一篇文章: https://www.jianshu.com/p/dc06a54e920a
详细讲解 OKHttp的核心内容,拦截器。不过拦截器众多,有系统自带的,也有我们可以自己去自定义的。
image.png
这是网络请求执行的核心方法的起点,这里涉及了众多拦截器,
正文大纲
系统自带拦截器
1 重试与重定向拦截器
RetryAndFollowUpInterceptor
2 桥接拦截器BridgeInterceptor
3 缓存拦截器CacheInterceptor
4 连接拦截器ConnectInterceptor
5 服务调用拦截器CallServerInterceptor
可自定义的拦截器
- 继承
Intercetor
- 继承
NetworkInterceptor
正文
在详解拦截器之前,有必要先将 RealCall
的 getResponseWithInterceptorChain()
方法最后两行展开说明:
Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
这里最终返回 一个Response
,进入chain.proceed
方法,最终索引到 RealInterceptorChain
的proceed
方法:
image.png
之后,我们追踪这个interceptor.intercept(next);
,发现是一个接口,找到实现类,有多个,进入其中的RetryAndFollowUpInterceptor
,发现:
image.png
它这里又执行了 chain.proceed,于是又回到了RealInterceptorChain.proceed()
方法,但是此时,刚才链条中的拦截器已经不再是原来的拦截器了,而是变成了第二个,因为每一次都index+1
了(这里比较绕,类似递归,需要反复仔细体会),依次类推,直到所有拦截器的intercept方法都执行完毕,直到链条中没有拦截器。就返回最后的Response
。
这一段是okhttp责任链模式的核心,应该好理解。
系统自带拦截器
1. 重试与重定向拦截器 RetryAndFollowUpInterceptor
先说结论吧:
顾名思义,retry 重试, FollowUp 重定向 。这个拦截器处在所有拦截器的第一个,它是用来判定要不要对当前请求进行重试和重定向的,那么我们应该关心的是:
什么时候重试
,什么时候重定向
。
先来关注一下RetryAndFollowUpInterceptor
的核心方法 interceptor()
:
@Override public Response intercept(Chain chain) throws IOException {
...省略
while (true) {
...省略
try {
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), false, request)) {
throw e.getLastConnectException();
}
releaseConnection = false;
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, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
}
...省略
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
return response;
}
...省略
}
}
上面的代码中,我只保留了关键部分。其中有两个continue,一个return.
当请求到达了这个拦截器,它会进入一个
while(true)
循环,当发生了RouteException
异常(这是由于请求尚未发出去,路由异常,连接未成功),就会去判断recover
方法的返回值,根据返回值决定要不要continue
.
当发生IOException
(请求已经发出去,但是和服务器通信失败了)之后,同样去判断recover
方法的返回值,根据返回值决定要不要continue
.
recover()
方法内部:
如果这两个
continue
都没有执行,就有可能走到最后的return response
结束本次请求.