OkHttp4.9.3源码解析

OkHttp4.9.3

okhttp内部逻辑流程图:

1. 整体结构

主要类有:

  1. OkHttpClient
  2. Request 和 Response
  3. RealCall

简单介绍:

  • OkHttpClient:核心管理类,所有内部逻辑和对象归OkHttpClient统一管理,由Builder构造器生成。
  • Request 和 Response:两个累完全符合http协议所定义的请求内容和响应内容
    • Request:发送请求封装类,包含url、method、headers、body
    • Response:返回结果,包含code、message、headers、body
  • RealCall:OkHttp 的应用层和网络层之间的桥梁。负责请求的调度(同步走当前线程发送请求,异步使用OkHttp内部的线程池进行),同时负责构造内部逻辑责任链,并执行责任链相关逻辑,知道获取结果。虽然OkHttpClient师整个OkHttp的核心管理类,但是真正发出请求并且组织逻辑的师RealCall类,它同时肩负了调度和责任链组织的两大重任。

重点:

RealCall两个重要方法:execute() 和 enqueue()

  • execute() :处理同步请求
  • enqueue() :处理异步请求。只是通过异步线程和callback做了一个异步调用的封装,最终逻辑还是会调用到execute(),然后会调用 getResponseWithInterceptorChain()获得请求结果

getResponseWithInterceptorChain()承载了整个请求的核心逻辑。是okhttp的大体请求流程。

  internal fun getResponseWithInterceptorChain(): Response {
   
    // 创建一个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)

    //创建RealInterceptorChain,传入拦截器列表
    val chain = RealInterceptorChain(
        call = this,
        interceptors = interceptors,
        index = 0,
        exchange = null,
        request = originalRequest,
        connectTimeoutMillis = client.connectTimeoutMillis,
        readTimeoutMillis = client.readTimeoutMillis,
        writeTimeoutMillis = client.writeTimeoutMillis
    )

    var calledNoMoreExchanges = false
    try {
   
      //调用RealInterceptorChain.proceed,传入参数:originalRequest(应用程序未受重定向或身份验证标头的影响的原始请求)
      //获取返回结果
      val response = chain.proceed(originalRequest)
      if (isCanceled()) {
   
        response.closeQuietly()
        throw IOException("Canceled")
      }
      return response
    } catch (e: IOException) {
   
      calledNoMoreExchanges = true
      throw noMoreExchanges(e) as Throwable
    } finally {
   
      if (!calledNoMoreExchanges) {
   
        noMoreExchanges(null)
      }
    }
  }

Interceptors拦截器的List列表,按顺序依次将:

  • client.Interceptors
  • RetryAndFollowUpInterceptor,
  • BridgeInterceptor
  • CacheInterceptor
  • ConnectInterceptor
  • client.networkInterceptors(forWebSocket==false)
  • CallServerInterceptor

结论:okhttp将整个请求的复杂逻辑切成了一个个独立的模块并命名为连接器(Interceptor),通过责任链的设计模式串联到一起,最终完成了请求获取先买个因结果。

2. 拦截器

创建完RealInterceptorChain后,调用RealInterceptorChain.proceed获得响应结果,其流程如下:

//copy函数
  internal fun copy(
    index: Int = this.index,
    exchange: Exchange? = this.exchange,
    request: Request = this.request,
    connectTimeoutMillis: Int = this.connectTimeoutMillis,
    readTimeoutMillis: Int = this.readTimeoutMillis,
    writeTimeoutMillis: Int = this.writeTimeoutMillis
  ) = RealInterceptorChain(call, interceptors, index, exchange, request, connectTimeoutMillis,
      readTimeoutMillis, writeTimeoutMillis)


//RealInterceptorChain.proceed
  @Throws(IOException::class)
  override fun proceed(request: Request): Response {
   
    check(index < interceptors.size)

    calls++

    if (exchange != null) {
   
      check(exchange.finder.sameHostAndPort(request.url)) {
   
        "network interceptor ${
     interceptors[index - 1]} must retain the same host and port"
      }
      check(calls == 1) {
   
        "network interceptor ${
     interceptors[index - 1]} must call proceed() exactly once"
      }
    }

    // Call the next interceptor in the chain.
    val next = copy(index = index + 1, request = request)
    val interceptor = interceptors[index]

    @Suppress("USELESS_ELVIS")
    val response = interceptor.intercept(next) ?: throw NullPointerException(
        "interceptor $interceptor returned null")

    if (exchange != null) {
   
      check(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
  }

其本质上就是通过将多个拦截器以责任链的方式来一层层调用,上一个拦截器处理完后将就将结果传给下一个拦截器,直到最后一个拦截器(即 CallServerInterceptor )处理完后将 Response 再一层层往上传递。

具体步骤

  1. 拦截器按照添加顺序依次执行
  2. 拦截器的执行从RealInterceptorChain.proceed()开始,进入到第一个拦截器的执行逻辑
  3. 每个拦截器在执行之前,会将剩余尚未执行的拦截器组成新的RealInterceptorChain
  4. 拦截器的逻辑被新的责任链调用next.proceed()切分为start、next.proceed、end这三个部分依次执行
  5. next.proceed() 所代表的其实就是剩余所有拦截器的执行逻辑
  6. 所有拦截器最终形成一个层层内嵌的嵌套结构



拦截器都继承了Interceptor接口:

fun interface Interceptor {
   
  @Throws(IOException::class)
  fun intercept(chain: Chain): Response //每个拦截器具体逻辑实现在intercept()

  companion object {
   
    /**
     * ```kotlin
     * val interceptor = Interceptor { chain: Interceptor.Chain ->
     *     chain.proceed(chain.request())
     * }
     * ```
     */
    inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor =
      Interceptor {
    block(it) }
  }

  interface Chain {
   
    fun request(): Request

    @Throws(IOException::class)
    fun proceed(request: Request): Response

    /**
     * Returns the connection the request will be executed on. This is only available in the chains
     * of network interceptors; for application interceptors this is always null.
     */
    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
  }
}

拦截器主要分为两类:自定义拦截器和OkHttp内部拦截器,自定义拦截器可以在创建OkHttpClient.Builder时,通过addInterceptor 和 addNetworkdInterceptor 添加自定义的拦截器

自定义拦截器:

  • client.Interceptors
  • client.networkInterceptors:满足 forWebSocket==false 才添加


OkHttp内部拦截器:

  • RetryAndFollowUpInterceptor:失败和重定向拦截器
  • BridgeInterceptor:封装request和response拦截器
  • CacheInterceptor:缓存相关的拦截器,负责读取缓存直接返回、更新缓存
  • ConnectInterceptor:连接服务,负责和服务器建立连接,真正的请求网络
  • CallServerInterceptor:执行流操作(写出请求体、获取相应数据)负责向服务器发送请求数据,从服务器读取响应数据,进行http请求报文的封装和请求报文的解析


2.1 RetryAndFollowUpInterceptor

RetryAndFollowUpInterceptor:失败和重定向拦截器

为什么要重新发送请求

  1. 路由失败,这里稍微解释一下路由就是一个web服务可能会有代理或者多个IP地址,这些就可以组成所谓的路由,只要我们能够连通其中任意一条路由即可与服务器通信,所以在路由失败之后还可以选择其他的路由进行连接
  2. 获取到3xx的重定向要求进行重定向请求,服务器或者代理要求认证信息
class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Interceptor {
   

  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
   
    val realChain = chain as RealInterceptorChain
    var request = chain.request
    val call = realChain.call
    var followUpCount = 0
    var priorResponse: Response? = null
    var newExchangeFinder = true
    var recoveredFailures = listOf<IOException>()
    //设置一个死循环,对上面两个可能的情况进行不断的重新发送请求
    while (true) {
   
      call.enterNetworkInterceptorExchange(request, newExchangeFinder)

      var response: Response
      var closeActiveExchange = true
      try {
   
        if (call.isCanceled()) {
   
          throw IOException("Canceled")
        }

        try {
   
            //链式调用
          response = realChain.proceed(request)
          newExchangeFinder = true
        } catch (e: RouteException) {
   
          //抛出路由异常-->是否满足重试条件
          if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {
   
            throw e.firstConnectException.withSuppressed(recoveredFailures)
          } else {
   
            recoveredFailures += e.firstConnectException
          }
          newExchangeFinder = false
          continue
        } catch (e: IOException) {
   
          //抛出IO异常-->是否满足重试条件
          if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
   
            throw e.withSuppressed(recoveredFailures)
          } else {
   
            recoveredFailures += e
          }
          newExchangeFinder = false
          continue
        }

        // Attach the prior response if it exists. Such responses never have a body.
        if (priorResponse != null) {
   
          response = response.newBuilder()
              .priorResponse(priorResponse.newBuilder()
                  .body(null)
                  .build())
              .build()
        }

        val exchange = call.interceptorScopedExchange
        //调用followUpRequest()进行跟进处理,这里面根据服务器返回码进行相应的处理,具体的要翻看http协议返回码对应的意义
        val followUp = followUpRequest(response, exchange)

        //根据followUp的结果判断是否需要重新发送请求或者直接返回response
        if (followUp == null) {
   
          if (exchange != null && exchange.isDuplex) {
   
            call.timeoutEarlyExit()
          }
          closeActiveExchange = false
          return response
        }

        val followUpBody = followUp.body
        if (followUpBody != null && followUpBody.isOneShot()) {
   
          closeActiveExchange = false
          return response
        }

        response.body?.closeQuietly()

        if (++followUpCount > MAX_FOLLOW_UPS) {
   
          throw ProtocolException("Too many follow-up requests: $followUpCount")
        }

        request = followUp
        priorResponse = response
      } finally {
   
        call.exitNetworkInterceptorExchange(closeActiveExchange)
      }
    }
  }
}

(recover)是否满足重试条件的判定逻辑如下:

  private fun recover(
    e: IOException,
    call: RealCall,
    userRequest: Request,
    requestSendStarted: Boolean
  ): Boolean {
   
    // 设置重试的参数为false
    if (!client.retryOnConnectionFailure) return false

    // 请求的body已经发出
    if (requestSendStarted && requestIsOneShot(e, userRequest)) return false

    // 特殊异常类型:ProtocolException,SSLHandshakeException等
    if (!isRecoverable(e, requestSendStarted)) return false

    //没有更多的route(包含proxy和inetaddress)
    if (!call.retryAfterFailure()) return false

    // 否则重试当前请求
    return true
  }

2.4 Interceptors和networkInterceptors

在OkHttpClient.Builder的构造方法有两个参数,使用者可以通过addInterceptor 和 addNetworkdInterceptor 添加自定义的拦截器

从前面添加拦截器的顺序可以知道 Interceptors 和 networkInterceptors 刚好一个在 RetryAndFollowUpInterceptor 的前面,一个在后面。

结合前面的责任链调用图可以分析出来,假如一个请求在 RetryAndFollowUpInterceptor 这个拦截器内部重试或者重定向了 N 次,那么其内部嵌套的所有拦截器也会被调用N次,同样 networkInterceptors 自定义的拦截器也会被调用 N 次。而相对的 Interceptors 则一个请求只会调用一次,所以在OkHttp的内部也将其称之为 Application Interceptor。

Interceptors(应用拦截器)

  1. 不需要担心中间响应,如重定向和重试。

  2. 总是调用一次,即使从缓存提供HTTP响应。

  3. 遵守应用程序的原始意图。不注意OkHttp注入的头像If-None-Match。

  4. 允许短路和不通话Chain.proceed()。

  5. 允许重试并进行多次呼叫Chain.proceed()。

networkInterceptors(网络拦截器)

  1. 能够对重定向和重试等中间响应进行操作。

  2. 不调用缓存的响应来短路网络。

  3. 观察数据,就像通过网络传输一样。

  4. 访问Connection该请求。

2.3 BridgeInterceptor

BridgeInterceptor:封装request和response拦截器

负责把用户构造的请求转换为发送到服务器的请求 、把服务器返回的响应转换为用户友好的响应,是从应用程序代码到网络代码的桥梁

BridgeInterceptor拦截器的逻辑流程如下:

  1. 设置内容长度,内容编码
  2. 设置gzip压缩,并在接收到内容后进行解压。省去了应用层处理数据解压的麻烦
  3. 添加cookie
  4. 设置其他报头,如User-Agent,Host,Keep-alive等。其中Keep-Alive是实现连接复用的必要步骤
class BridgeInterceptor(
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值