
拦截器
- 用户自定义的拦截器
- 应用拦截器 在所有拦截器的前面
- 网络拦截器 在 RetryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、ConnectInterceptor拦截器的后面,CallServerInterceptor拦截器的后面
1、 RetryAndFollowUpInterceptor
连接失败后进行重试、对请求结果跟进后进行重定向
- 如果通过 RouteException
- 通过单个路由出现了多次链接都失败以后出现此异常
- 根据 recover 判断是否需要重连
- 如果没有添加应用拦截器,那么RetryAndFollowUpInterceptor就是第一个拦截器,主要功能是判断是否需要重试和重定向。
如果请求阶段发生了IOException,就会通过recover方法判断是进行连接重试。
重定向发生在重试的判定之后,如果不满足重试的条件,还需要进一步调用followUpRequest根据Response 的响应码(
当然,如果直接请求失败,Response都不存在就会抛出异常)判断是否重定向;followup最大发生次数20次。
2、 BridgeInterceptor
BridgeInterceptor,连接应用程序和服务器的桥梁,我们发出的请求会经过它的处理才能发给服务器,
比如设置请求内容的长度,编码,gzip压缩,cookie等;获取响应后保存cookie、解压等操作。
相对比较简单。
- 对用户构建的Request进行添加或者删除相关头部信息,以转化成能够真正进行网络请求的Request。
- 将符合网络请求规范的Request交给下一个拦截器处理,并获取Response。
- 如果响应体经过了gzip压缩,那就需要解压,再构建成用户可用的Response并返回。
首先,chain.proceed()执行前,对请求头进行补全,补全请求头如下:
| 请求头 | 说明 |
|---|---|
| Content-Type | 请求体类型,如:application/x-www-form-urlencoded |
| Content-Length/Transfer-Encoding | 请求体解析方式 |
| Host | 请求的主机站点 |
| Connection: Keep-Alive | 保持长连接 |
| Accept-Encoding: gzip | 接受响应支持gzip压缩 |
| Cookie | cookie身份辨别 |
| User-Agent | 请求的用户信息,如:操作系统、浏览器等 |
先把响应header中的cookie存入cookieJar(如果有),在下次请求则会读取对应的数据设置进入请求头,默认的CookieJar不提供实现,需要我们在初始化OkhttpClient时配置我们自己的cookieJar。
如果使用gzip返回的数据,则使用GzipSource包装便于解析
3、 CacheInterceptor
CacheInterceptor,在发出请求前,先判断是否命中缓存,如果命中则可以不请求,直接使用缓存的响应(默认只会对Get请求进行缓存);如果未命中则进行网络请求,并将结果缓存,等待下次请求被命中。
大概梳理一下步骤:
- 从缓存中获取对应请求的响应缓存
- 创建CacheStrategy,创建时会判断是否能够使用缓存,在CacheStrategy中有两个成员:networkRequest和cacheResponse。他们有如下组合进行判断:
| networkRequest | cacheResponse | 说明 |
|---|---|---|
| Null | Null | 网络请求、缓存 都不能用,okhttp直接返回504 |
| Null | Not Null | 直接使用缓存 |
| Not Null | Null | 向服务器发起请求 |
| Not Null | Not Null | 向服务器发起请求,若得到响应码为304(无修改),则更新缓存响应并返回 |
- 交给下一个责任链继续处理
- 后续工作,返回304则用缓存的响应;否则使用网络响应并缓存本次响应(只缓存Get请求的响应)
- 缓存拦截器中判断使用缓存或者请求服务器都是通过CacheStrategy判断。分析CacheStrategy前我们先来了解下Http的缓存机制,以便更好的理解:

okhttp_cache.png

okhttp_cache_2.png
4、 ConnectInterceptor
这个拦截器主要的作用就是负责从连接池获取健康的连接(判断连接的 Socket 传输通道是否可用),如果在连接池中没有找到符合复用的连接(除了主机地址之外的信息必须要全部匹配,例如 DNS、代理、协议、证书),那么就会使用路由再找一遍(路由的结构是一个代理服务器的地址 + DNS 中的一个 IP 地址),如果还是没有,那么会直接创建一个新的连接对象并进行三次握手,再将这个新的连接对象添加到连接池中,最后将可复用的连接返回回去
4、 CallServerInterceptor
CalllServerInterceptor是最后一个拦截器了,前面的拦截器已经完成了socket连接和tls连接,那么这一步就是传输http的头部和body数据了。