1. OkHttp的运用

/**
 * OkHttp测试类
 * @author LTP  2023/6/29
 */
class OkHttpTest {
    /** 创立OkHttpClient方针 */
    private val okHttpClient = OkHttpClient.Builder().build()
    /** 创立Request方针 */
    private val request = Request.Builder().url("http://www.baidu.com").build()
    /** 创立RealCall方针(Call的仅有接口完结类) */
    private val realCall = okHttpClient.newCall(request)
    /**
     * 同步恳求
     */
    @Test
    fun getRequestWithSync() {
        // 运用同步恳求,realCall履行
        realCall.execute().use {
            print(it.body?.string())
        }
    }
    /**
     * 异步恳求
     */
    @Test
    fun getRequestWithASync() {
        // 运用异步恳求,将realCall参加恳求行列
        realCall.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                e.printStackTrace()
            }
            override fun onResponse(call: Call, response: Response) {
                print(response.body?.string() ?: "123")
            }
        })
        // 得阻塞一会儿线程不让其结束以拿到恳求成果
        Thread.sleep(2000)
    }
}
  • 首要进程有
    1. 创立OkHttpClient方针
    2. 创立Request方针
    3. 创立RealCall方针
    4. 开端建议恳求,enqueue为异步恳求,execute为同步恳求

2. 恳求进程

  • 源码依据OkHttp V4.11.0(直接下载到本地引入lib,BTPJ/OkHttpStudy)

2.1 OkHttpClient方针的创立

OkHttpClient() // 办法1
OkHttpClient.Builder().build() // 办法2
OkHttpClient().newBuilder().build() // 办法3
  • 三种办法本质上都是一样的,这儿以办法2为例
  • 从创立办法来猜想便是一个典型的制作者形式,OkHttpClient.Builder()创立了一个okHttpClient的内部Builder类方针,里边初始化了一系列的成员变量,着重剖析以下三个
/***
 * 制作者形式
 */
class Builder constructor() {
    /** 调度器 */
    internal var dispatcher: Dispatcher = Dispatcher()
    /** 拦截器调集 */
    internal val interceptors: MutableList<Interceptor> = mutableListOf()
    /** 网络拦截器调集 */
    internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
  • 接着运用Builder方针调用了build()办法
/** 调用OkHttpClient结构创立OkHttpClient方针 */
fun build(): OkHttpClient = OkHttpClient(this)
  • 其实便是调用的OkHttpClient(builder:Builder)结构
open class OkHttpClient internal constructor(
    builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
    @get:JvmName("dispatcher")
    val dispatcher: Dispatcher = builder.dispatcher
    @get:JvmName("interceptors")
    val interceptors: List<Interceptor> =
        builder.interceptors.toImmutableList()
    @get:JvmName("networkInterceptors")
    val networkInterceptors: List<Interceptor> =
        builder.networkInterceptors.toImmutableList()
  • 其实便是典型的制作者形式,经过Builder创立的调度器、拦截器等成员变量最终都会赋值给OkHttpClient

2.2 Request方针的创立

Request.Builder().url("http://www.baidu.com").build()
  • 也是个制作者形式…
open class Builder {
  // 恳求地址
  internal var url: HttpUrl? = null
  // 恳求办法(例如Get、Post)
  internal var method: String
  // 恳求头Header调集
  internal var headers: Headers.Builder
  // 恳求体Body
  internal var body: RequestBody? = null
  internal var tags: MutableMap<Class<*>, Any> = mutableMapOf()
  constructor() {
    this.method = "GET"
    this.headers = Headers.Builder()
  }
  • 看下build()办法
open fun build(): Request {
  return Request(
      checkNotNull(url) { "url == null" },
      method,
      headers.build(),
      body,
      tags.toImmutableMap()
  )
}
  • 其实便是创立了一个Request方针,并把Bulder方针的成员属性赋值给Request

2.3 创立Call方针

okHttpClient.newCall(request)
  • 看下newCall
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
  • 回来了Call接口的仅有完结类RealCall
class RealCall(
  val client: OkHttpClient,
  val originalRequest: Request,
  val forWebSocket: Boolean
) : Call {
...
  • 看下Call接口详细界说了哪些办法
/** Call.kt
 * 调用预备好的履行恳求。恳求能够被撤销。因为此方针表明单个恳求/呼应对(流),因此不能履行两次
 */
interface Call : Cloneable {
  /** 回来启动此调用的原始恳求. */
  fun request(): Request
  /** 同步恳求(恳求会被立即调用,一向阻塞线程直至恳求被呼应或恳求犯错) */
  @Throws(IOException::class)
  fun execute(): Response
 /**
  * 异步恳求,安排在将来某个时刻点履行的恳求,详细调度者是OkHttpClient.dispatcher调度器,
  * 调度恳求回来到Callback中
  */
  fun enqueue(responseCallback: Callback)
  /** 撤销恳求(现已完结的恳求无法被撤销) */ 
  fun cancel()
  /** 恳求是否被履行(包含executed和enqueued),多次履行该办法是过错的 */
  fun isExecuted(): Boolean
  /** 恳求是否被撤销 */
  fun isCanceled(): Boolean
  /** 恳求超时时刻 */
  fun timeout(): Timeout
  /** 克隆一个新Call(无论旧Call是否已被履行) */
  public override fun clone(): Call
  /** 方针创立工厂 */
  fun interface Factory {
    fun newCall(request: Request): Call
  }
}
  • RealCall对Call中界说的这些办法进行了完结,详细可看RealCall的完结逻辑,这儿就不贴出来了

2.4 建议恳求

  • 先剖析下建议异步恳求
// RealCall.kt
override fun enqueue(responseCallback: Callback) {
  // 检测是否已被履行过,履行过抛反常
  check(executed.compareAndSet(false, true)) { "Already Executed" }
  // 事情监听回调相关,监听恳求建议事情
  callStart()
  // 将恳求交给调度器,调度器决定什么时候开端恳求
  client.dispatcher.enqueue(AsyncCall(responseCallback))
}
private fun callStart() {
  this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()")
  // 事情监听回调
  eventListener.callStart(this)
}
  • 真实的逻辑在Dispatcher中
/** Dispatcher.kt
 * 何时履行异步恳求的调度器,内部默许是运用ExecutorService完结的
 */
class Dispatcher constructor() {
  /** 一起履行的最大恳求数,超越的恳求会在内存中排队等候 */
  @get:Synchronized var maxRequests = 64
    set(maxRequests) {
      require(maxRequests >= 1) { "max < 1: $maxRequests" }
      synchronized(this) {
        field = maxRequests
      }
      promoteAndExecute()
    }
  /** 每台主机可并发履行的最大恳求数(经过URL的主机名) */
  @get:Synchronized var maxRequestsPerHost = 5
    set(maxRequestsPerHost) {
      require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" }
      synchronized(this) {
        field = maxRequestsPerHost
      }
      promoteAndExecute()
    }
  /** 恳求行列空闲回调 */
  @set:Synchronized
  @get:Synchronized
  var idleCallback: Runnable? = null
  private var executorServiceOrNull: ExecutorService? = null
  /** 线程池(懒汉式保证单例) */
  @get:Synchronized
  @get:JvmName("executorService") val executorService: ExecutorService
    get() {
      if (executorServiceOrNull == null) {
        executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
            SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
      }
      return executorServiceOrNull!!
    }
  /** 待发送到恳求行列的异步恳求 */
  private val readyAsyncCalls = ArrayDeque<AsyncCall>()
  /** 异步恳求行列 */
  private val runningAsyncCalls = ArrayDeque<AsyncCall>()
 /** 同步恳求行列 */
  private val runningSyncCalls = ArrayDeque<RealCall>()
  ...
  • 看下dispatcher.enqueue办法
/** Dispatcher.kt
 * 参加行列
 */
internal fun enqueue(call: AsyncCall) {
    synchronized(this) {
        // 增加进预备发送的调集
        readyAsyncCalls.add(call)
        // 修正AsyncCall,使其同享对同一主机的现有运转调用的AtomicInteger
        if (!call.call.forWebSocket) {
            val existingCall = findExistingCallWithHost(call.host)
            if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
        }
    }
    // 处理行列移动并按序履行
    promoteAndExecute()
}
/**Dispatcher.kt
 * 将符合条件的call从readyAsyncCalls(预备发送的行列)增加到runningAsyncCalls(异步发送行列)中,
 * 并在executor服务上运转它们。不能在同步的情况下调用,因为履行调用或许会调用用户代码
 *
 * @return true if the dispatcher is currently running calls. 假如调度程序当时正在运转,则为true
 */
private fun promoteAndExecute(): Boolean {
    this.assertThreadDoesntHoldLock()
    // 正在运转的恳求
    val executableCalls = mutableListOf<AsyncCall>()
    val isRunning: Boolean
    synchronized(this) {
        val i = readyAsyncCalls.iterator()
        while (i.hasNext()) {
            val asyncCall = i.next()
            // 超越最大恳求数64,跳出整个循环
            if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
            // 单服务器超越最大恳求数,跳出当时单个循环
            if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
            // 从恳求预备行列中移除
            i.remove()
            asyncCall.callsPerHost.incrementAndGet()
            executableCalls.add(asyncCall)
            // 参加异步恳求行列中
            runningAsyncCalls.add(asyncCall)
        }
        isRunning = runningCallsCount() > 0
    }
    for (i in 0 until executableCalls.size) {
        val asyncCall = executableCalls[i]
        // 把恳求使命交给线程池
        asyncCall.executeOn(executorService)
    }
    return isRunning
}
/** RealCall.kt
 * 测验将此异步调用参加[executorService]的行列。假如履行器已封闭,则会测验调用失利回调来进行整理
 */
fun executeOn(executorService: ExecutorService) {
  client.dispatcher.assertThreadDoesntHoldLock()
  var success = false
  try {
    // 运用线程履行
    executorService.execute(this)
    success = true
  } catch (e: RejectedExecutionException) {
    val ioException = InterruptedIOException("executor rejected")
    ioException.initCause(e)
    noMoreExchanges(ioException)
    // 履行失利的回调调用
    responseCallback.onFailure(this@RealCall, ioException)
  } finally {
    if (!success) {
      // 发送恳求结束
      client.dispatcher.finished(this)
    }
  }
}
  • 最终是交给线程池executorService来处理的,executorService.execute办法接收的是一个Runnable完结类,这个类便是AsyncCall,它也是RealCall的非静态内部类,持有对RealCall的引证
/**
 * RealCall.kt
 * Runnable完结类,会被参加到线程池履行
 */
internal inner class AsyncCall(
  private val responseCallback: Callback
) : Runnable {
  ...
  val host: String
    get() = originalRequest.url.host
  val request: Request
      get() = originalRequest
  val call: RealCall
      get() = this@RealCall
  /**
   * 测验将此异步调用参加[executorService]的行列。假如履行器已封闭,则会测验调用失利回调来进行整理
   */
  fun executeOn(executorService: ExecutorService) {
    ...
  }
  override fun run() {
    threadName("OkHttp ${redactedUrl()}") {
      var signalledCallback = false
      timeout.enter()
      try {
        // 发送恳求,经过一系列的拦截器链最终回来呼应成果
        val response = getResponseWithInterceptorChain()
        signalledCallback = true
        // 回调恳求成功的成果
        responseCallback.onResponse(this@RealCall, response)
      } catch (e: IOException) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
        } else {
          responseCallback.onFailure(this@RealCall, e)
        }
      } catch (t: Throwable) {
        // 失利后撤销恳求
        cancel()
        if (!signalledCallback) {
          val canceledException = IOException("canceled due to $t")
          canceledException.addSuppressed(t)
          // 恳求反常,回调恳求失利的成果
          responseCallback.onFailure(this@RealCall, canceledException)
        }
        throw t
      } finally {
        // 发送恳求结束
        client.dispatcher.finished(this)
      }
    }
  }
}
  • 看下恳求结束的办法client.dispatcher.finished(this)
// Dispatcher.kt
/** 被[AsyncCall.run]调用表明恳求完结(异步) */
internal fun finished(call: AsyncCall) {
    call.callsPerHost.decrementAndGet()
    finished(runningAsyncCalls, call)
}
/** 被[Call.execute]调用表明恳求完结(同步) */
internal fun finished(call: RealCall) {
    finished(runningSyncCalls, call)
}
/** 恳求结束的逻辑处理(将当时恳求从恳求行列移除、持续履行下一个恳求、判断是否回调搁置Callback) */
private fun <T> finished(calls: Deque<T>, call: T) {
    val idleCallback: Runnable?
    synchronized(this) {
        // 从恳求使命行列中移除
        if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
        idleCallback = this.idleCallback
    }
    // 持续将等候行列中的恳求移入异步行列,并交由线程池履行
    val isRunning = promoteAndExecute()
    // 假如没有恳求需求被履行,回调恳求行列搁置的callback
    if (!isRunning && idleCallback != null) {
        idleCallback.run()
    }
}
  • 简略剖析下同步恳求
realCall.execute()
// RealCall.kt
/** 同步恳求 */
override fun execute(): Response {
  check(executed.compareAndSet(false, true)) { "Already Executed" }
  timeout.enter()
  callStart()
  try {
    // 直接交由dispatcher履行
    client.dispatcher.executed(this)
    // 经过getResponseWithInterceptorChain回来恳求呼应
    return getResponseWithInterceptorChain()
  } finally {
    // 发送恳求结束
    client.dispatcher.finished(this)
  }
}
// Dispatcher.kt
/** 被 [Call.execute] 调用表明正在履行恳求. */
@Synchronized
internal fun executed(call: RealCall) {
    // 直接参加恳求行列
    runningSyncCalls.add(call)
}
  • 可见同步恳求会将恳求Call参加到同步恳求行列,并直接调用getResponseWithInterceptorChain()回来呼应成果
  • 来张图对整个流程做个总结
    OkHttp源码阅读

3. 拦截器链

  • 上面知道回来呼应是经过getResponseWithInterceptorChain()这个办法的,看下源码
// RealCall.kt
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
  // 构建一个完好的拦截器链
  val interceptors = mutableListOf<Interceptor>()
  // 用户自界说的拦截器(大局拦截器,能够在任何恳求进程中运用)
  interceptors += client.interceptors
  // 重试和重定向拦截器
  interceptors += RetryAndFollowUpInterceptor(client)
  // 桥接拦截器,首要担任恳求和呼应的转换
  interceptors += BridgeInterceptor(client.cookieJar)
  // 缓存拦截器,首要担任缓存的相关处理
  interceptors += CacheInterceptor(client.cache)
  // 衔接拦截器,首要担任树立衔接,树立 TCP 衔接或许 TLS 衔接
  interceptors += ConnectInterceptor
  if (!forWebSocket) {
    // 用户自界说的网络拦截器(针对特定类型的恳求运用的拦截器)
    interceptors += client.networkInterceptors
  }
  // 调用服务器拦截器,首要担任网络数据的恳求和呼应,也便是实践的网络I/O操作
  interceptors += CallServerInterceptor(forWebSocket)
  // 结构详细的拦截器链
  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 {
    // 拦截器链的履行要害,拦截器的层层调用、层层回来
    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)
    }
  }
}
  • getResponseWithInterceptorChain办法是整个OkHttp完结职责链形式的核心,在这个办法中除了很多拦截器是要点之外还有chain.proceed,它利用了职责链形式进行层层调用proceed,层层回来response
// RealInterceptorChain.kt
@Throws(IOException::class)
override fun proceed(request: Request): Response {
  ...
  // 创立并调用拦截器链中的下一个拦截器的intercept办法
  val next = copy(index = index + 1, request = request)
  val interceptor = interceptors[index]
  @Suppress("USELESS_ELVIS")
  // 调用下一个拦截器的intercept办法(intercept内部还会调用proceed)
  val response = interceptor.intercept(next) ?: throw NullPointerException(
      "interceptor $interceptor returned null")
  ...
  return response
}
  • 从源码得知,Chain 是用来描述职责链的,并经过其间的 process 办法开端顺次履行链上的每个节点,并回来处理后的 Response。 Chain 的仅有完结为 RealInterceptorChain,能够称之为拦截器职责链,其间的节点由 RealCall 中增加进来的 Interceptor 们组成
  • Interceptor 与 Chain 相相互互依赖,相互调用,形成了一个完美的调用链,下面是大致的调用关系链

OkHttp源码阅读

3.1 RetryAndFollowUpInterceptor

  • 除掉自界说拦截器之外第一个履行的拦截器。首要作用是进行恳求的重试与重定向(还创立了一个衔接办理池)。在某些情况下,当网络恳求失利时,这个拦截器能够供给一种机制,测验从头衔接到网络,并再次发送恳求。这个进程能够帮助运用程序在出现短暂的网络问题时坚持衔接,进步了体系的可靠性和稳定性。
// RetryAndFollowUpInterceptor.kt
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) {
            // newExchangeFinder传true,enterNetworkInterceptorExchange办法会创立一个新的
            // ExchangeFinder方针(办理链接池)
            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) {
                   ...
                val exchange = call.interceptorScopedExchange
                // 计算出接收[userResponse]时要宣布的HTTP恳求。
                // 这将增加身份验证标头、遵从重定向或处理客户端恳求超时。假如后续操作不必要或不适用,则回来null
                val followUp = followUpRequest(response, exchange)
                // 获取到的request为空则直接回来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若不为空则从头赋值后持续建议恳求
                request = followUp
                priorResponse = response
            } finally {
                call.exitNetworkInterceptorExchange(closeActiveExchange)
            }
        }
    }
    ...
    /**
     * 计算出接收[userResponse]时要宣布的HTTP恳求。
     * 这将增加身份验证标头、遵从重定向或处理客户端恳求超时。假如后续操作不必要或不适用,则回来null
     */
    @Throws(IOException::class)
    private fun followUpRequest(userResponse: Response, exchange: Exchange?): Request? {
        val route = exchange?.connection?.route()
        val responseCode = userResponse.code
        val method = userResponse.request.method
        when (responseCode) {
            HTTP_PROXY_AUTH -> {
               // 407反常处理
               ...
            }
            HTTP_UNAUTHORIZED -> return client.authenticator.authenticate(route, userResponse)
            HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> {
                // 300、301、302、303、307、308,重定向恳求处理
                return buildRedirectRequest(userResponse, method)
            }
            HTTP_CLIENT_TIMEOUT -> {
                // 408反常处理
                ...
            }
            HTTP_UNAVAILABLE -> {
                // 503反常处理
                ...
            }
            HTTP_MISDIRECTED_REQUEST -> {
                // 421反常处理
                ...
            }
            else -> return null
        }
    }
    /** 构建重定向恳求 */
    private fun buildRedirectRequest(userResponse: Response, method: String): Request? {
        ...
        // 大多数重定向不包含恳求正文
        val requestBuilder = userResponse.request.newBuilder()
        if (HttpMethod.permitsRequestBody(method)) {
            val responseCode = userResponse.code
            val maintainBody = HttpMethod.redirectsWithBody(method) ||
                    responseCode == HTTP_PERM_REDIRECT ||
                    responseCode == HTTP_TEMP_REDIRECT
            if (HttpMethod.redirectsToGet(method) && responseCode != HTTP_PERM_REDIRECT && responseCode != HTTP_TEMP_REDIRECT) {
                requestBuilder.method("GET", null)
            } else {
                val requestBody = if (maintainBody) userResponse.request.body else null
                requestBuilder.method(method, requestBody)
            }
            if (!maintainBody) {
                requestBuilder.removeHeader("Transfer-Encoding")
                requestBuilder.removeHeader("Content-Length")
                requestBuilder.removeHeader("Content-Type")
            }
        }
        // 跨主机重定向时,需求删除所有身份验证标头(运用层无法保存它们)
        if (!userResponse.request.url.canReuseConnectionFor(url)) {
            requestBuilder.removeHeader("Authorization")
        }
        return requestBuilder.url(url).build()
    }
    companion object {
        /**
         * 重试或许重定向的次数
         */
        private const val MAX_FOLLOW_UPS = 20
    }
}

3.2 BridgeInterceptor

  • 桥接拦截器,首要担任恳求和呼应的转换。把用户结构的 request 方针转换成发送到服务器 request方针,并把服务器回来的呼应转换为对用户友爱的呼应。
// BridgeInterceptor.kt
/**
 * 从运用程序代码到网络代码的桥接。
 * 首要,它依据用户恳求构建一个网络恳求。然后它持续呼叫网络。最终,它依据网络呼应构建用户呼应
 */
class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor {
    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        // 恳求阶段:BridgeInterceptor担任将用户构建的Request恳求转化为能够进行网络访问的恳求。
        // 这个进程或许包含一些对恳求头部的处理,例如设置恳求头信息,如Content-Type,Content-Length等
        val userRequest = chain.request()
        val requestBuilder = userRequest.newBuilder()
        val body = userRequest.body
        if (body != null) {
            val contentType = body.contentType()
            if (contentType != null) {
                requestBuilder.header("Content-Type", contentType.toString())
            }
            val contentLength = body.contentLength()
            if (contentLength != -1L) {
                requestBuilder.header("Content-Length", contentLength.toString())
                requestBuilder.removeHeader("Transfer-Encoding")
            } else {
                requestBuilder.header("Transfer-Encoding", "chunked")
                requestBuilder.removeHeader("Content-Length")
            }
        }
        if (userRequest.header("Host") == null) {
            requestBuilder.header("Host", userRequest.url.toHostHeader())
        }
        if (userRequest.header("Connection") == null) {
            requestBuilder.header("Connection", "Keep-Alive")
        }
        // 假如增加了“Accept-Encoding:gzip”的Header,拦截器还担任解压缩传输流
        var transparentGzip = false
        if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
            transparentGzip = true
            requestBuilder.header("Accept-Encoding", "gzip")
        }
        val cookies = cookieJar.loadForRequest(userRequest.url)
        if (cookies.isNotEmpty()) {
            requestBuilder.header("Cookie", cookieHeader(cookies))
        }
        if (userRequest.header("User-Agent") == null) {
            requestBuilder.header("User-Agent", userAgent)
        }
        // 回来阶段:当网络恳求回来呼应时,BridgeInterceptor会将网络恳求回来的Response转化为用户可用的Response。
        // 这个进程或许包含对回来数据进行解析,处理呼应头信息,或许将处理后的呼应回来给用户
        val networkResponse = chain.proceed(requestBuilder.build())
        cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)
        val responseBuilder = networkResponse.newBuilder()
            .request(userRequest)
        if (transparentGzip &&
            "gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
            networkResponse.promisesBody()
        ) {
            val responseBody = networkResponse.body
            if (responseBody != null) {
                val gzipSource = GzipSource(responseBody.source())
                val strippedHeaders = networkResponse.headers.newBuilder()
                    .removeAll("Content-Encoding")
                    .removeAll("Content-Length")
                    .build()
                responseBuilder.headers(strippedHeaders)
                val contentType = networkResponse.header("Content-Type")
                responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))
            }
        }
        return responseBuilder.build()
    }

3.3 CacheInterceptor

  • 缓存拦截器,首要担任缓存的读取与写入,将 Http 的恳求成果放到到缓存中,以便在下次进行相同的恳求时,直接从缓存中读取成果,进步呼应速度。
// CacheInterceptor.kt
/**
 * 首要担任缓存的读取和写入,
 * 将 Http 的恳求成果放到到缓存中,以便在下次进行相同的恳求时,直接从缓存中读取成果,进步呼应速度
 */
class CacheInterceptor(internal val cache: Cache?) : Interceptor {
  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val call = chain.call()
    // 获取候选缓存
    val cacheCandidate = cache?.get(chain.request())
    val now = System.currentTimeMillis()
    // 缓存战略,恳求是运用网络、缓存仍是两者兼用
    val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()
    val networkRequest = strategy.networkRequest
    val cacheResponse = strategy.cacheResponse
    cache?.trackResponse(strategy)
    val listener = (call as? RealCall)?.eventListener ?: EventListener.NONE
    if (cacheCandidate != null && cacheResponse == null) {
      // 候选缓存不适用,直接封闭
      cacheCandidate.body?.closeQuietly()
    }
    // 假如咱们被禁止运用网络,而且缓存缺乏,抛出反常504。
    if (networkRequest == null && cacheResponse == null) {
      return Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(HTTP_GATEWAY_TIMEOUT)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(EMPTY_RESPONSE)
          .sentRequestAtMillis(-1L)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build().also {
            listener.satisfactionFailure(call, it)
          }
    }
    // 假如不需求网络则直接回来缓存即可
    if (networkRequest == null) {
      // 回来缓存恳求成果
      return cacheResponse!!.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build().also {
            listener.cacheHit(call, it)
          }
    }
    if (cacheResponse != null) {
      listener.cacheConditionalHit(call, cacheResponse)
    } else if (cache != null) {
      listener.cacheMiss(call)
    }
    var networkResponse: Response? = null
    try {
      // 职责链,让下一个拦截器处理
      networkResponse = chain.proceed(networkRequest)
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (networkResponse == null && cacheCandidate != null) {
        cacheCandidate.body?.closeQuietly()
      }
    }
    // 有缓存呼应
    if (cacheResponse != null) {
      // 服务器回来状态码为304则回来缓存成果
      if (networkResponse?.code == HTTP_NOT_MODIFIED) {
        val response = cacheResponse.newBuilder()
            .headers(combine(cacheResponse.headers, networkResponse.headers))
            .sentRequestAtMillis(networkResponse.sentRequestAtMillis)
            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis)
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build()
        networkResponse.body!!.close()
        // 在兼并标头之后但在剥离Content-Encoding标头之前更新缓存
        cache!!.trackConditionalCacheHit()
        cache.update(cacheResponse, response)
        return response.also {
          listener.cacheHit(call, it)
        }
      } else {
        cacheResponse.body?.closeQuietly()
      }
    }
    // 读取网络恳求成果
    val response = networkResponse!!.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build()
    if (cache != null) {
      if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {
        // 将网络恳求成果参加缓存
        val cacheRequest = cache.put(response)
        return cacheWritingResponse(cacheRequest, response).also {
          if (cacheResponse != null) {
            listener.cacheMiss(call)
          }
        }
      }
      // 缓存失效时需求铲除
      if (HttpMethod.invalidatesCache(networkRequest.method)) {
        try {
          cache.remove(networkRequest)
        } catch (_: IOException) {
        }
      }
    }
    // 回来网络恳求成果
    return response
  }

3.4 ConnectInterceptor

  • 衔接拦截器,首要担任树立衔接,树立 TCP 衔接或许 TLS 衔接
// ConnectInterceptor.kt
/**
 * 翻开与方针服务器的衔接,然后转到下一个拦截器。网络或许用于回来的呼应,或许运用条件GET验证缓存的呼应
 */
object ConnectInterceptor : Interceptor {
  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val realChain = chain as RealInterceptorChain
    // 查找新衔接或池衔接以承载即将到来的恳求和呼应
    val exchange = realChain.call.initExchange(chain)
    val connectedChain = realChain.copy(exchange = exchange)
    // 让下一层拦截器处理,一起将exchange一起传递过去
    return connectedChain.proceed(realChain.request)
  }
}
  • 树立衔接的部分核心代码
// realCall.kt
/** 查找新衔接或池衔接以承载即将到来的恳求和呼应 */
internal fun initExchange(chain: RealInterceptorChain): Exchange {
  ...
  val codec = exchangeFinder.find(client, chain)
  val result = Exchange(this, eventListener, exchangeFinder, codec)
  return result
}
// ExchangeFinder.kt
fun find(
  client: OkHttpClient,
  chain: RealInterceptorChain
): ExchangeCodec {
  try {
    val resultConnection = findHealthyConnection(
        connectTimeout = chain.connectTimeoutMillis,
        readTimeout = chain.readTimeoutMillis,
        writeTimeout = chain.writeTimeoutMillis,
        pingIntervalMillis = client.pingIntervalMillis,
        connectionRetryEnabled = client.retryOnConnectionFailure,
        doExtensiveHealthChecks = chain.request.method != "GET"
    )
    return resultConnection.newCodec(client, chain)
 ...
}
// ExchangeFinder.kt
/**  查找可用的链接,假如不可用则一向重复查找,知道找到停止 */
@Throws(IOException::class)
private fun findHealthyConnection(
  connectTimeout: Int,
  readTimeout: Int,
  writeTimeout: Int,
  pingIntervalMillis: Int,
  connectionRetryEnabled: Boolean,
  doExtensiveHealthChecks: Boolean
): RealConnection {
  while (true) {
    val candidate = findConnection(
        connectTimeout = connectTimeout,
        readTimeout = readTimeout,
        writeTimeout = writeTimeout,
        pingIntervalMillis = pingIntervalMillis,
        connectionRetryEnabled = connectionRetryEnabled
    )
    // 确保衔接可用
    if (candidate.isHealthy(doExtensiveHealthChecks)) {
      return candidate
    }
    ...
  }
}
// ExchangeFinder.kt
/** 获取衔接,先是获取现已存在的进行重用,没有从池中取,再没有就创立一个新衔接 */
@Throws(IOException::class)
private fun findConnection(
  connectTimeout: Int,
  readTimeout: Int,
  writeTimeout: Int,
  pingIntervalMillis: Int,
  connectionRetryEnabled: Boolean
): RealConnection {
    ...
    // 假如衔接还没有被开释则会重用。这儿没有调用connectionAcquired()是因为咱们之前现已获取了
    if (call.connection != null) {
      check(toClose == null)
      return callConnection
    }
    ...
  // 能从衔接池拿到衔接直接回来
  if (connectionPool.callAcquirePooledConnection(address, call, null, false)) {
    val result = call.connection!!
    eventListener.connectionAcquired(call, result)
    return result
  }
  // 衔接池中无衔接时,创立新衔接并增加到衔接池
  ...
  val newConnection = RealConnection(connectionPool, route)
  call.connectionToCancel = newConnection
  try {
    // 运用新衔接来进行服务器衔接
    newConnection.connect(
        connectTimeout,
        readTimeout,
        writeTimeout,
        pingIntervalMillis,
        connectionRetryEnabled,
        call,
        eventListener
    )
  } finally {
  ...
  synchronized(newConnection) {
     // 新衔接增加到衔接池
    connectionPool.put(newConnection)
    call.acquireConnectionNoEvents(newConnection)
  }
  eventListener.connectionAcquired(call, newConnection)
    return newConnection
  }
  • exchangeFinder.find开端到exchangeFinder.findConnection只做了一件事,便是先测验重用衔接,假如不能重用就从衔接池中取出一个新的衔接,假如无法取出就直接创立一个新的衔接并增加到衔接池中。
  • 看看服务器是怎样衔接的,看这行代码newConnection.connect
// RealConnection.kt
fun connect(
  connectTimeout: Int,
  readTimeout: Int,
  writeTimeout: Int,
  pingIntervalMillis: Int,
  connectionRetryEnabled: Boolean,
  call: Call,
  eventListener: EventListener
) {
...
  while (true) {
    try {
      if (route.requiresTunnel()) {
        ...
      } else {
        // 经过Socket构建完好HTTP或HTTPS衔接
        connectSocket(connectTimeout, readTimeout, call, eventListener)
  ...
}
// RealConnection.kt
/** 经过Socket来构建完好HTTP或HTTPS衔接 */
@Throws(IOException::class)
private fun connectSocket(
  connectTimeout: Int,
  readTimeout: Int,
  call: Call,
  eventListener: EventListener
) {
 ...
  try {
    Platform.get().connectSocket(rawSocket, route.socketAddress, connectTimeout)
  } catch (e: ConnectException) {
 ...
try {
  // okio的接口,用于输入,相似InputStream
  source = rawSocket.source().buffer()
  //okio的接口,用于输出,相似OutputStream
  sink = rawSocket.sink().buffer()
}
...
}
  • 首要是创立了一个socket方针然后运用socket树立衔接,利用okio的输入输出接口获取输入/输出流

3.5 CallServerInterceptor

  • 首要担任网络数据的恳求和呼应,也便是实践的网络I/O操作。将恳求头与恳求体发送给服务器,以及解析服务器回来的response
// CallServerInterceptor.kt
/** 最终一个拦截器,完结对服务器的网络调用 */
class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor {
  @Throws(IOException::class)
  override fun intercept(chain: Interceptor.Chain): Response {
    val realChain = chain as RealInterceptorChain
    val exchange = realChain.exchange!!
    val request = realChain.request
    val requestBody = request.body
    val sentRequestMillis = System.currentTimeMillis()
    var invokeStartEvent = true
    var responseBuilder: Response.Builder? = null
    var sendRequestException: IOException? = null
    try {
      exchange.writeRequestHeaders(request)
      // 假如不是GET/HEAD恳求
      if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
        if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
          exchange.flushRequest()
          responseBuilder = exchange.readResponseHeaders(expectContinue = true)
          exchange.responseHeadersStart()
          invokeStartEvent = false
        }
        if (responseBuilder == null) {
          if (requestBody.isDuplex()) {
            // 预备双工正文,以便运用程序稍后能够发送恳求正文
            exchange.flushRequest()
            val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
            requestBody.writeTo(bufferedRequestBody)
          } else {
            val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
            requestBody.writeTo(bufferedRequestBody)
            bufferedRequestBody.close()
          }
        } else {
          exchange.noRequestBody()
          if (!exchange.connection.isMultiplexed) {
            exchange.noNewExchangesOnConnection()
          }
        }
      } else {
        exchange.noRequestBody()
      }
      if (requestBody == null || !requestBody.isDuplex()) {
        exchange.finishRequest()
      }
    } catch (e: IOException) {
      if (e is ConnectionShutdownException) {
        throw e // No request was sent so there's no response to read.
      }
      if (!exchange.hasFailure) {
        throw e // Don't attempt to read the response; we failed to send the request.
      }
      sendRequestException = e
    }
    try {
      if (responseBuilder == null) {
        responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
        if (invokeStartEvent) {
          exchange.responseHeadersStart()
          invokeStartEvent = false
        }
      }
      var response = responseBuilder
          .request(request)
          .handshake(exchange.connection.handshake())
          .sentRequestAtMillis(sentRequestMillis)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build()
      var code = response.code
      if (shouldIgnoreAndWaitForRealResponse(code)) {
        responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
        if (invokeStartEvent) {
          exchange.responseHeadersStart()
        }
        response = responseBuilder
            .request(request)
            .handshake(exchange.connection.handshake())
            .sentRequestAtMillis(sentRequestMillis)
            .receivedResponseAtMillis(System.currentTimeMillis())
            .build()
        code = response.code
      }
      exchange.responseHeadersEnd(response)
      response = if (forWebSocket && code == 101) {
        response.newBuilder()
            .body(EMPTY_RESPONSE)
            .build()
      } else {
        response.newBuilder()
            .body(exchange.openResponseBody(response))
            .build()
      }
     ...
      return response
   ...
  }

3.6 拦截器总结

  1. client.interceptors:用户自界说的拦截器,会在所有的拦截器处理之前进行最早的拦截处理,可用于增加一些公共参数,如自界说 header、自界说 log 等等。
  2. RetryAndFollowUpIntercept:重试和重定向拦截器,重试或许重定向的次数不能大于20次,一起它还创立了一个ExchangeFinder方针用于办理衔接池为后续的衔接做预备
  3. BridgeInterceptor:桥接拦截器,首要担任恳求和呼应的转换。补充恳求头,把用户恳求转换成网络恳求,网络呼应转换成用户能够接收的呼应,一起还需求注意的一点是假如用户手动增加了Accept-Encoding那就需求处理解压操作
  4. CacheInterceptor:缓存拦截器,首要担任缓存的读取与写入,将 Http 的恳求成果放到到缓存中,以便在下次进行相同的恳求时,直接从缓存中读取成果,进步呼应速度(内部是经过okio来处理缓存的)
  5. ConnectInterceptor:衔接拦截器,担任树立衔接的。最终是经过RealConnection方针树立socket衔接的,而且获得了输入输出流为下一步读写做预备,RealConnection方针的获取时优先复用的,假如无法复用则从衔接池中获取,假如无法获取则创立一个新的衔接并将其放入衔接池中
  6. client.networkInterceptors:用户自界说的网络拦截器(针对特定类型的恳求运用的拦截器)
  7. CallServerInterceptor:调用服务器拦截器,首要担任网络数据的恳求和呼应,也便是实践的网络I/O操作。将恳求头与恳求体发送给服务器,以及解析服务器回来的 response

3.6.1 interceptors与networkInterceptors对比

  • 两者都是用户自界说的拦截器,前者是在第一个,后者是在倒数第2个
  • interceptors是运用拦截器,networkInterceptors是网络拦截器;
  • 运用拦截器是用于在恳求发送前和网络呼应后的拦截器,只能触发一次。而网络拦截器在产生过错重试或许重定向时能够履行多次,相当于进行了二次恳求;
  • 假如CacheInterceptor命中了缓存就不再进行网络恳求了,因此会存在短路网络拦截器的情况;
  • 运用拦截器一般用于统计客户端的网络恳求建议情况;网络拦截器中能够获取到最终发送恳求的request也包含重定向的数据,也能够获取真实产生网络恳求的回来的response,然后修正对应的恳求和呼应数据。
  • 用法上:interceptors可用于增加一些公共参数,如自界说 header、自界说 log 等,而networkInterceptors首要针对特定类型的恳求运用的拦截器