OkHttp原理分析(二)

330 阅读2分钟

重试和重定向拦截器

class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Interceptor {

  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    var request = chain.request()
    val realChain = chain as RealInterceptorChain
    val transmitter = realChain.transmitter()
    var followUpCount = 0
    var priorResponse: Response? = null
    // 重试和重定向
    while (true) {
      transmitter.prepareToConnect(request)
      if (transmitter.isCanceled) {
        throw IOException("Canceled")
      }
      var response: Response
      var success = false
      try {
        response = realChain.proceed(request, transmitter, null)
        success = true
      } catch (e: RouteException) {
        // 路由失败,请求还没有发出
        if (!recover(e.lastConnectException, transmitter, false, request)) {
          throw e.firstConnectException
        }
        continue
      } catch (e: IOException) {
        // 服务器失败,请求已经发出
        val requestSendStarted = e !is ConnectionShutdownException
        // 报告并尝试从与服务器通信失败中恢复。如果“e”是可恢复的,则返回true;如果失败是永久性的,则返回false。
        // 只有在缓冲了正文或在发送请求之前发生故障时,才可以恢复具有正文的请求。
        if (!recover(e, transmitter, requestSendStarted, request)) throw e
        continue
      } finally {
        // 网络抛出异常,释放资源,exchange赋值为null
        if (!success) {
          transmitter.exchangeDoneDueToException()
        }
      }
      // 附加先前响应如果存在,这样的反应从来没有实体。
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                .body(null)
                .build())
            .build()
      }
      val exchange = response.exchange
      val route = exchange?.connection()?.route()
      val followUp = followUpRequest(response, route)
      if (followUp == null) {
        if (exchange != null && exchange.isDuplex) {
          transmitter.timeoutEarlyExit()
        }
        return response
      }
      val followUpBody = followUp.body
      if (followUpBody != null && followUpBody.isOneShot()) {
        return response
      }
      // 清空响应体
      response.body?.closeQuietly()
      if (transmitter.hasExchange()) {
        // 撤消此Exchange对流的访问
        exchange?.detachWithViolence()
      }
      if (++followUpCount > MAX_FOLLOW_UPS) {
        throw ProtocolException("Too many follow-up requests: $followUpCount")
      }
      request = followUp
      priorResponse = response
    }
  }
}
fun prepareToConnect(request: Request) {
  if (this.request != null) {
    // 判断路由是否可用
    if (this.request!!.url.canReuseConnectionFor(request.url) && exchangeFinder!!.hasRouteToTry()) {
      return 
    }
    check(exchange == null)
    if (exchangeFinder != null) {
      // 强制释放链接
      maybeReleaseConnection(null, true)
      exchangeFinder = null
    }
  }
  // 初始化交换查找器
  this.request = request
  this.exchangeFinder = ExchangeFinder(
    this, connectionPool, createAddress(request.url), call, eventListener)
}
private fun followUpRequest(userResponse: Response, route: Route?): Request? {
  val responseCode = userResponse.code
  val method = userResponse.request.method
  when (responseCode) {
    // 代理认证,默认返回null
    HTTP_PROXY_AUTH -> {
      val selectedProxy = route!!.proxy
      if (selectedProxy.type() != Proxy.Type.HTTP) {
        throw ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy")
      }
      return client.proxyAuthenticator.authenticate(route, userResponse)
    }
    // 认证,默认返回null
    HTTP_UNAUTHORIZED -> return client.authenticator.authenticate(route, userResponse)
    // 重定向
    HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT -> {
      if (method != "GET" && method != "HEAD") {
        return null
      }
      return buildRedirectRequest(userResponse, method)
    }
    // 重定向
    HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> {
      return buildRedirectRequest(userResponse, method)
    }
    // 超时
    HTTP_CLIENT_TIMEOUT -> {
      if (!client.retryOnConnectionFailure) {
        // 默认超时不重试
        return null
      }

      val requestBody = userResponse.request.body
      if (requestBody != null && requestBody.isOneShot()) {
        return null
      }
      val priorResponse = userResponse.priorResponse
      if (priorResponse != null && priorResponse.code == HTTP_CLIENT_TIMEOUT) {
        // 前一次超时,放弃
        return null
      }
      if (retryAfter(userResponse, 0) > 0) {
        return null
      }
      return userResponse.request
    }
    // HTTP不可用
    HTTP_UNAVAILABLE -> {
      val priorResponse = userResponse.priorResponse
      if (priorResponse != null && priorResponse.code == HTTP_UNAVAILABLE) {
        // 前一次超时,放弃
        return null
      }
      if (retryAfter(userResponse, Integer.MAX_VALUE) == 0) {
        // 接收到特殊指令,无延迟重试
        return userResponse.request
      }
      return null
    }
    else -> return null
  }
}

重试和重定向总结

HTTP响应码 followUpRequest
HTTP_PROXY_AUTH(407) 添加代理认证,默认放弃
HTTP_UNAUTHORIZED(401) 添加认证,默认放弃
HTTP_PERM_REDIRECT(308)HTTP_TEMP_REDIRECT(307) 重定向
HTTP_MULT_CHOICE(300)HTTP_MOVED_PERM(301)HTTP_MOVED_TEMP(302)HTTP_SEE_OTHER(303) 重定向
HTTP_CLIENT_TIMEOUT(408) 默认放弃,或延迟0秒重试
HTTP_UNAVAILABLE(503) 延迟0秒重试
其他 成功或放弃