从网络请求过程看OkHttp拦截器

作者: jimuzz
来源:https://www.cnblogs.com/jimuzz/p/14557234.html
前言之前我们结合设计模式简单说了下 OkHttp 的大体流程,今天就继续说说它的核心部分—— 拦截器  。
因为拦截器组成的链其实是完成了网络通信的整个流程,所以我们今天就从这个角度说说各拦截器的功能 。
首先,做一下简单回顾,从
getResponseWithInterceptorChain 方法开始 。
简单回顾(getResponseWithInterceptorChain)internal fun getResponseWithInterceptorChain(): Response {// Build a full stack of interceptors.val interceptors = mutableListOf<Interceptor>()interceptors += client.interceptorsinterceptors += RetryAndFollowUpInterceptor(client)interceptors += BridgeInterceptor(client.cookieJar)interceptors += CacheInterceptor(client.cache)interceptors += ConnectInterceptorif (!forWebSocket) {interceptors += client.networkInterceptors}interceptors += CallServerInterceptor(forWebSocket)val chain = RealInterceptorChain(interceptors = interceptors//...)val response = chain.proceed(originalRequest)}这些拦截器会形成一条链,组织了请求接口的所有工作 。

从网络请求过程看OkHttp拦截器

文章插图
 
以上为上节内容,不了解的朋友可以返回上一篇文章看看 。
假如我来设计拦截器先抛开拦截器的这些概念不谈,我们回顾下 网络通信过程 ,看看实现一个网络框架至少要有哪些功能 。
请求过程响应过程而之前说过拦截器的基本代码格式是这样:
override fun intercept(chain: Interceptor.Chain): Response {//做事情Aresponse = realChain.proceed(request)//做事情B}也就是分为 请求前工作,请求传递,获取响应后工作 三部分 。
那我们试试能不能把上面的功能分一分,设计出几个拦截器?
  • 拦截器1 : 处理请求前的 请求报文封装 ,处理响应后的 响应报文分析
诶,不错吧,拦截器1就用来处理 请求报文和响应报文的一些封装和解析工作 。就叫它封装拦截器吧 。
  • 拦截器2 : 处理请求前的 建立TCP连接
肯定需要一个拦截器用来建立TCP连接,但是响应后好像没什么需要做连接方面的工作了?那就先这样,叫它连接拦截器吧 。
  • 拦截器3 :处理请求前的 数据请求(写到数据流中) 处理响应后的 数据获取(从数据流拿数据)
这个拦截器就负责TCP连接后的 I/O操作,也就是从流中读取和获取数据 。就叫它 数据IO拦截器 吧 。
好了,三个拦截器好像足够了,我得意满满的偷看了一眼okhttp拦截器代码,7个???我去 。。
那再思考思考 ...,还有什么情况没考虑到呢?比如失败重试?返回301重定向?缓存的使用?用户自己对请求的统一处理?
所以又可以模拟出几个新的拦截器:
  • 拦截器4 :处理响应后的 失败重试和重定向功能
没错,刚才只考虑到请求成功,请求失败了要不要重试呢?响应码为301、302时候的重定向处理?这都属于要重新请求的部分,肯定不能丢给用户,需要网络框架自己给处理好 。就叫它 重试和重定向拦截器吧 。
  • 拦截器5 :处理响应前的 缓存复用 ,处理响应后的 缓存响应数据  。
还有一个网络请求有可能的需求就是关于缓存,这个缓存的概念可能有些朋友了解的不多,其实它多用于浏览器中 。
浏览器缓存一般分为两部分: 强制缓存和协商缓存  。
强制缓存 就是服务器会告诉客户端该怎么缓存,例如 cache-Control 字段,随便举几个例子:
privatemax-age=xxxno-cacheno-store协商缓存 就是需要客户端和服务器进行协商后再决定是否使用缓存,比如强制缓存过期失效了,就要再次请求服务器,并带上缓存标志,例如Etag 。
客户端再次进行请求的时候,请求头带上 If-None-Match ,也就是之前服务器返回的Etag值 。
Etag值就是文件的唯一标示,服务器通过某个算法对资源进行计算,取得一串值(类似于文件的md5值),之后将该值通过etag返回给客户端
然后服务器就会将 Etag 值和服务器本身文件的 Etag 值进行比较,如果一样则数据没改变,就返回 304 ,代表你要请求的数据没改变,你直接用就行啦 。
如果不一致,就返回新的数据,这时候的响应码就是正常的 200  。


推荐阅读