再学Android:OkHttp源码探究(二)getResponseWithInterceptorChain

前言

上一篇文章中咱们简单的总结了ok发起请求并接收响应的整个流程,咱们发现关键步骤是getResponseWithInterceptorChain这个方法。那这里面又作了什么事情呢?仍是首先来看一下代码:设计模式

@Throws(IOException::class)
  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(interceptors, transmitter, null, 0, originalRequest, this,
        client.connectTimeoutMillis, client.readTimeoutMillis, client.writeTimeoutMillis)

    var calledNoMoreExchanges = false
    try {
      val response = chain.proceed(originalRequest)
      if (transmitter.isCanceled) {
        response.closeQuietly()
        throw IOException("Canceled")
      }
      return response
    } catch (e: IOException) {
      calledNoMoreExchanges = true
      throw transmitter.noMoreExchanges(e) as Throwable
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null)
      }
    }
  }
复制代码

能够说这个方法是整个okhttp的核心,经过这么几行代码就实现了整个请求的过程。这里不得不提到ok的拦截器机制。大多数人说到okhttp优秀的地方基本上都会脱口而出经过设置拦截器能够很方便的实现网络请求的打印、添加一些公共参数等等。而拦截器真正的运行其实就是在这个方法中。缓存

  • 首先在interceptors中添加用户自定义的拦截器
  • 而后按顺序添加各类系统内置的拦截器
  • 经过RealInterceptorChain方法获取一个chain对象
  • 经过chain.proceed获取response

拦截器

说了这么久的拦截器,确定会好奇它到底是个什么妖魔鬼怪:服务器

/** * Observes, modifies, and potentially short-circuits requests going out and the corresponding * responses coming back in. Typically interceptors add, remove, or transform headers on the request * or response. */
interface Interceptor {
  @Throws(IOException::class)
  fun intercept(chain: Chain): Response

  companion object {
    inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor =
        object : Interceptor {
          override fun intercept(chain: Chain) = block(chain)
        }
  }
  interface Chain {
    fun request(): Request

    @Throws(IOException::class)
    fun proceed(request: Request): Response
    fun connection(): Connection?
    fun call(): Call
    fun connectTimeoutMillis(): Int
    fun withConnectTimeout(timeout: Int, unit: TimeUnit): Chain
    fun readTimeoutMillis(): Int
    fun withReadTimeout(timeout: Int, unit: TimeUnit): Chain
    fun writeTimeoutMillis(): Int
    fun withWriteTimeout(timeout: Int, unit: TimeUnit): Chain
  }
}

复制代码

Interceptor其实是一个接口,里面定义了一个intercept方法和chain的接口类。cookie

intercept

关于intercept方法是否是很熟悉?咱们在自定义拦截器的时候每每都是在这里面作一些瞎操做。网络

override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val realInterceptorChain = chain as RealInterceptorChain
        val transmitter = realInterceptorChain.transmitter()
        val response = realInterceptorChain.proceed(request, transmitter, null)
        return response

    }
复制代码
  • 这里首先是经过chain.request获取请求的request对象
  • 经过chain.proceed 递归调用下一个拦截器的intercept方法
  • 最终返回chain.proceed的response到上一级拦截器
分层

这里实际上是将每一个拦截器分为了两个阶段:ide

  • Request阶段:执行该拦截器在请求前作的事,例如:bridgeInterceptor添加一些请求参数
  • Response阶段:执行拦截器在获取响应以后作的事,例如:打印出请求体的返回

拦截器的设计实际上是采用了递归调用的思想,仔细想一想实际上是很是巧妙的,这样能够保证不管是系统内置仍是用户自定义的拦截器均可以获得最终执行。若是在某个拦截器中出现了错误,还能够把错误抛给上一层来处理。学习

内置拦截器

经过剖析源码咱们会发现,ok内部实际上是帮咱们内置了好几种拦截器,每次请求都会添加进去,咱们按照添加顺序整理以下:ui

拦截器 说明
RetryAndFollowUpInterceptor 负责实现重定向功能
BridgeInterceptor 将用户构造的请求转换为向服务器发送的请求,将服务器返回的响应转换为对用户友好的响应
CacheInterceptor 读取缓存、更新缓存
ConnectInterceptor 创建与服务器的链接
CallServerInterceptor 从服务器读取响应

能够看出,整个网络请求的过程是经过各个拦截器相互配合来实现,假如咱们在网络请求过程当中设置容许缓存,那么在请求网络以前会预先获取缓存,而后再去跟服务器创建链接。经过拦截器的机制,咱们能够很方便的控制整个网络请求的过程以及添加咱们本身的拓展。this

整个网络请求过程当中,用户实际上是能够添加两种不一样类型的拦截器的。url

  • 经过 addInterceptor()在网络请求先后添加拦截器
  • 经过networkInterceptors()在获取响应先后添加拦截器

这一点在getResponseWithInterceptorChain()方法中添加拦截器的顺序是能够分析出来的。

总体流程

图片来源: blog.n0texpecterr0r.cn/?p=717

RealInterceptorChain

通过上面的分析咱们知道okhttp的实际请求和响应过程是经过一个个拦截器的递归调用来实现的。主要方法就是

realInterceptorChain.proceed。咱们先来看一下RealInterceptorChain的构造方法

class RealInterceptorChain(
  private val interceptors: List<Interceptor>,
  private val transmitter: Transmitter,
  private val exchange: Exchange?,
  private val index: Int,
  private val request: Request,
  private val call: Call,
  private val connectTimeout: Int,
  private val readTimeout: Int,
  private val writeTimeout: Int
) 
复制代码

这里实际上是将上一个拦截器的一些参数传递进来而且赋值的简单实现。包括全部的拦截器、以及咱们在第一篇文章提到的transmitter等。整个类中最关键的仍是proceed方法

@Throws(IOException::class)
  fun proceed(request: Request, transmitter: Transmitter, exchange: Exchange?): Response {
    if (index >= interceptors.size) throw AssertionError()
    calls++
    // If we already have a stream, confirm that the incoming request will use it.
    check(this.exchange == null || this.exchange.connection()!!.supportsUrl(request.url)) {
      "network interceptor ${interceptors[index - 1]} must retain the same host and port"
    }
    // If we already have a stream, confirm that this is the only call to chain.proceed().
    check(this.exchange == null || calls <= 1) {
      "network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
    }
    // Call the next interceptor in the chain.
    val next = RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
    val interceptor = interceptors[index]
    @Suppress("USELESS_ELVIS")
    val response = interceptor.intercept(next) ?: throw NullPointerException(
        "interceptor $interceptor returned null")
    // Confirm that the next interceptor made its required call to chain.proceed().
    check(exchange == null || index + 1 >= interceptors.size || next.calls == 1) {
      "network interceptor $interceptor must call proceed() exactly once"
    }
    check(response.body != null) { "interceptor $interceptor returned a response with no body" }
    return response
  }
复制代码

能够看到这个方法中除了大量的判读逻辑,比较关键的就是经过index+1取到下一个RealInterceptorChain对象 。

而后获取当前的拦截器而且调用其intercept方法 ,方法参数中传入了下一个拦截器的对应的chain。就是这样经过递归调用的设计,实现了由上而下,再由下而上实现了递与归的过程。从而很是漂亮的实现了http请求的全链路。

看到这里有没有以为这种设计模式很熟悉,没错就是责任链模式。这种设计模式在一个流程会有多种操做的业务场景下会很是实用。

总结

本篇文章咱们主要是分析了整个网络请求过程当中很是重要的getResponseWithInterceptorChain()方法,内部经过责任链的模式递归调用用户自定义拦截器和内置拦截器来完成整个网络请求。经过对整个方法的分析,咱们会更清晰的知道ok内部是怎么实现经过设置拦截器来完成咱们想要的功能的。同时也是咱们学习责任链模式很是好的实践。后续文章将逐个分析ok内置拦截器的具体做用。

参考资料

OkHttp 源码剖析系列(一)——请求的发起及拦截器机制概述

相关文章
相关标签/搜索