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


这个拦截器就是用于处理这些情况,我们就叫它 缓存拦截器 吧 。

  • 拦截器6: 自定义拦截器
最后就是自定义的拦截器了,要给开发者一个可以自定义的拦截器,用于统一处理请求或响应数据 。
这下好像齐了,至于之前说的7个拦截器还有1个,留个悬念最后再说 。
最后再给他们排个序吧:
  • 1、自定义拦截器的公共参数处理 。
  • 2、封装拦截器封装请求报文
  • 3、缓存拦截器的缓存复用 。
  • 4、连接拦截器建立TCP连接 。
  • 5、IO拦截器的数据写入 。
  • 6、IO拦截器的数据读取 。
  • 7、缓存拦截器保存响应数据缓存 。
  • 8、封装拦截器分析响应报文
  • 9、重试和重定向拦截器处理重试和重定向情况 。
  • 10、自定义拦截器统一处理响应数据 。
有点绕,来张图瞧一瞧:
从网络请求过程看OkHttp拦截器

文章插图
 
所以,拦截器的顺序也基本固定了:
  • 1、自定义拦截器
  • 2、重试和重定向拦截器
  • 3、封装拦截器
  • 4、缓存拦截器
  • 5、连接拦截器
  • 6、IO拦截器
下面具体看看吧 。
自定义拦截器在请求之前,我们一般创建自己的自定义拦截器,用于添加一些接口公共参数,比如把 token 加到Header中 。
class MyInterceptor() : Interceptor {override fun intercept(chain: Interceptor.Chain): Response {var request = chain.request()request = request.newBuilder().addHeader("token", "token").url(url).build()return chain.proceed(request)}要注意的是,别忘了调用 chain.proceed ,否则这条链就无法继续下去了 。
在获取响应之后,我们一般用拦截器进行结果打印,比如常用的 HttpLoggingInterceptor  。
addInterceptor(HttpLoggingInterceptor().Apply {level = HttpLoggingInterceptor.Level.BODY})重试和重定向拦截器(RetryAndFollowUpInterceptor)为了方便理解,我对源码进行了修剪:scissors::
class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Interceptor {@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {while (true) {try {try {response = realChain.proceed(request)} catch (e: RouteException) {//路由错误continue} catch (e: IOException) {// 请求错误continue}//获取响应码判断是否需要重定向val followUp = followUpRequest(response, exchange)if (followUp == null) {//没有重定向return response}//赋予重定向请求,再次进入下一次循环request = followUp}}}}这样代码就很清晰了,重试和重定向的处理都是需要重新请求,所以这里用到了while循环 。
realChain.proceed重定向response封装拦截器(BridgeInterceptor)class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor {@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {//添加头部信息requestBuilder.header("Content-Type", contentType.toString())requestBuilder.header("Host", userRequest.url.toHostHeader())requestBuilder.header("Connection", "Keep-Alive")requestBuilder.header("Accept-Encoding", "gzip")requestBuilder.header("Cookie", cookieHeader(cookies))requestBuilder.header("User-Agent", userAgent)val networkResponse = chain.proceed(requestBuilder.build())//解压val responseBuilder = networkResponse.newBuilder().request(userRequest)if (transparentGzip &&"gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&networkResponse.promisesBody()) {val responseBody = networkResponse.bodyif (responseBody != null) {val gzipSource = GzipSource(responseBody.source())responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))}}return responseBuilder.build()}请求前的代码很简单,就是添加了一些必要的头部信息,包括 Content-Type、Host、Cookie 等等,封装成一个完整的请求报文,然后交给下一个拦截器 。
而获取响应后的代码就有点不是很明白了, gzip 是啥? GzipSource 又是什么类?
gzip压缩是基于deflate中的算法进行压缩的,gzip会产生自己的数据格式,gzip压缩对于所需要压缩的文件,首先使用LZ77算法进行压缩,再对得到的结果进行huffman编码,根据实际情况判断是要用动态huffman编码还是静态huffman编码,最后生成相应的gz压缩文件 。


推荐阅读