• 重温OKHTTP源码


    本文基于OkHttp4.12.0源码分析 官方地址

    概括

    本篇主要是对okhttp开源库的一个详细解析,包含详细的请求流程分析、各大拦截器的解读等。

    使用方法

    同步请求:创建一个OKHttpClient对象,一个Request对象,然后利用它们创建一个Call对象,最后调用execute()方法来拿到Response

    1. val client = OkHttpClient()
    2. val request = Request.Builder()
    3. .url("http://www.baidu.com")
    4. .build()
    5. val response = client.newCall(request).execute();

    异步调用:异步调用不同的在于使用enqueue方法并传入一个Callback接口来获取返回的Response。

    1. val client = OkHttpClient()
    2. val request = Request.Builder()
    3. .url("http://www.baidu.com")
    4. .build()
    5. client.newCall(request).enqueue(object : Callback {
    6. override fun onFailure(call: Call, e: IOException) {
    7. e.printStackTrace()
    8. }
    9. override fun onResponse(call: Call, response: Response) {
    10. Log.d("TAG", "response = " + response.message)
    11. Log.d("TAG", "response = " + response.body!!.toString())
    12. }
    13. })

    下面关于一些关键类的解析。

    OKHttpClient

    这是一个请求配置类,采用了建造者模式,方便用户配置一些请求参数,如配置callTimeout,cookie,interceptor等等。

    1. open class OkHttpClient internal constructor(
    2. builder: Builder
    3. ) : Cloneable, Call.Factory, WebSocket.Factory {
    4. @get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher
    5. @get:JvmName("connectionPool") val connectionPool: ConnectionPool = builder.connectionPool
    6. /**
    7. * Returns an immutable list of interceptors that observe the full span of each call: from before
    8. * the connection is established (if any) until after the response source is selected (either the
    9. * origin server, cache, or both).
    10. */
    11. @get:JvmName("interceptors") val interceptors: List =
    12. builder.interceptors.toImmutableList()
    13. ....
    14. constructor() : this(Builder())
    15. ....
    16. /** Prepares the [request] to be executed at some point in the future. */
    17. override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
    18. class Builder constructor() {
    19. internal var dispatcher: Dispatcher = Dispatcher()
    20. internal var connectionPool: ConnectionPool = ConnectionPool()
    21. internal val interceptors: MutableList = mutableListOf()
    22. internal val networkInterceptors: MutableList = mutableListOf()
    23. internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
    24. internal var retryOnConnectionFailure = true
    25. internal var authenticator: Authenticator = Authenticator.NONE
    26. internal var followRedirects = true
    27. internal var followSslRedirects = true
    28. internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
    29. internal var cache: Cache? = null
    30. internal var dns: Dns = Dns.SYSTEM
    31. internal var proxy: Proxy? = null
    32. internal var proxySelector: ProxySelector? = null
    33. internal var proxyAuthenticator: Authenticator = Authenticator.NONE
    34. internal var socketFactory: SocketFactory = SocketFactory.getDefault()
    35. internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
    36. internal var x509TrustManagerOrNull: X509TrustManager? = null
    37. internal var connectionSpecs: List = DEFAULT_CONNECTION_SPECS
    38. internal var protocols: List = DEFAULT_PROTOCOLS
    39. internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
    40. internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
    41. internal var certificateChainCleaner: CertificateChainCleaner? = null
    42. internal var callTimeout = 0
    43. internal var connectTimeout = 10_000
    44. internal var readTimeout = 10_000
    45. internal var writeTimeout = 10_000
    46. internal var pingInterval = 0
    47. internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
    48. internal var routeDatabase: RouteDatabase? = null
    49. ....

    Request

    这里作为请求参数的配置类,本身也采用了建造者模式,但相比OKHttpClient,Request就比较简单了,只有四个参数,分别是url、method、headers、body。

    1. class Request internal constructor(
    2. @get:JvmName("url") val url: HttpUrl,
    3. @get:JvmName("method") val method: String,
    4. @get:JvmName("headers") val headers: Headers,
    5. @get:JvmName("body") val body: RequestBody?,
    6. internal val tags: Map, Any>
    7. ) {
    8. ....
    9. open class Builder {
    10. internal var url: HttpUrl? = null
    11. internal var method: String
    12. internal var headers: Headers.Builder
    13. internal var body: RequestBody? = null
    14. ...

    Call

    请求调用接口,表示这个请求已经准备好可以执行,也可以取消,只能执行一次。

    1. interface Call : Cloneable {
    2. /** Returns the original request that initiated this call. */
    3. fun request(): Request
    4. /**
    5. * Invokes the request immediately, and blocks until the response can be processed or is in error.
    6. *
    7. * To avoid leaking resources callers should close the [Response] which in turn will close the
    8. * underlying [ResponseBody].
    9. *
    10. * ```
    11. * // ensure the response (and underlying response body) is closed
    12. * try (Response response = client.newCall(request).execute()) {
    13. * ...
    14. * }
    15. * ```
    16. *
    17. * The caller may read the response body with the response's [Response.body] method. To avoid
    18. * leaking resources callers must [close the response body][ResponseBody] or the response.
    19. *
    20. * Note that transport-layer success (receiving a HTTP response code, headers and body) does not
    21. * necessarily indicate application-layer success: `response` may still indicate an unhappy HTTP
    22. * response code like 404 or 500.
    23. *
    24. * @throws IOException if the request could not be executed due to cancellation, a connectivity
    25. * problem or timeout. Because networks can fail during an exchange, it is possible that the
    26. * remote server accepted the request before the failure.
    27. * @throws IllegalStateException when the call has already been executed.
    28. */
    29. @Throws(IOException::class)
    30. fun execute(): Response
    31. /**
    32. * Schedules the request to be executed at some point in the future.
    33. *
    34. * The [dispatcher][OkHttpClient.dispatcher] defines when the request will run: usually
    35. * immediately unless there are several other requests currently being executed.
    36. *
    37. * This client will later call back `responseCallback` with either an HTTP response or a failure
    38. * exception.
    39. *
    40. * @throws IllegalStateException when the call has already been executed.
    41. */
    42. fun enqueue(responseCallback: Callback)
    43. /** Cancels the request, if possible. Requests that are already complete cannot be canceled. */
    44. fun cancel()
    45. /**
    46. * Returns true if this call has been either [executed][execute] or [enqueued][enqueue]. It is an
    47. * error to execute a call more than once.
    48. */
    49. fun isExecuted(): Boolean
    50. fun isCanceled(): Boolean
    51. /**
    52. * Returns a timeout that spans the entire call: resolving DNS, connecting, writing the request
    53. * body, server processing, and reading the response body. If the call requires redirects or
    54. * retries all must complete within one timeout period.
    55. *
    56. * Configure the client's default timeout with [OkHttpClient.Builder.callTimeout].
    57. */
    58. fun timeout(): Timeout
    59. /**
    60. * Create a new, identical call to this one which can be enqueued or executed even if this call
    61. * has already been.
    62. */
    63. public override fun clone(): Call
    64. fun interface Factory {
    65. fun newCall(request: Request): Call
    66. }
    67. }

    RealCall

    RealCall是Call接口的具体实现类,是应用端与网络层的连接器,输入应用端原始的请求与连接数据,以及网络层返回的response及其他数据流。通过使用方法可知,创建完RealCall对象后,就要调用同步或异步请求方法,所以它里面还包含同步请求execute()与异步请求enqueue()方法。

    1. class RealCall(
    2. val client: OkHttpClient,
    3. /** The application's original request unadulterated by redirects or auth headers. */
    4. val originalRequest: Request,
    5. val forWebSocket: Boolean
    6. ) : Call {
    7. ....
    8. override fun execute(): Response {
    9. check(executed.compareAndSet(false, true)) { "Already Executed" }
    10. timeout.enter()
    11. callStart()
    12. try {
    13. client.dispatcher.executed(this)
    14. return getResponseWithInterceptorChain()
    15. } finally {
    16. client.dispatcher.finished(this)
    17. }
    18. }
    19. override fun enqueue(responseCallback: Callback) {
    20. check(executed.compareAndSet(false, true)) { "Already Executed" }
    21. callStart()
    22. client.dispatcher.enqueue(AsyncCall(responseCallback))
    23. }
    24. ....

    AsyncCall

    异步请求调用,是RealCall的一个内部类,本身实现了Runnable接口,被调度器中的线程池所执行。

    1. internal inner class AsyncCall(
    2. private val responseCallback: Callback
    3. ) : Runnable {
    4. ....

    Dispatcher

    调度器,用来调度Call对象,同时包含线程池和异步请求队列,用来存放与执行AsyncCall对象。

    流程分析

    同步请求

    val response = client.newCall(request).execute();

    newCall方法就是创建一个RealCall对象,然后执行其execute方法

    1. override fun execute(): Response {
    2. //CAS判断是否已经被执行了,确保只能执行一次,如果已经被执行了,则抛出异常
    3. check(executed.compareAndSet(false, true)) { "Already Executed" }
    4. //开启超时监听
    5. timeout.enter()
    6. //开启请求监听
    7. callStart()
    8. try {
    9. //调用调度器中的executed方法,调度器只是将call加入到runningSyncCalls队列中
    10. client.dispatcher.executed(this)
    11. //调用getResponseWithInterceptorChain方法拿到response
    12. return getResponseWithInterceptorChain()
    13. } finally {
    14. //执行完毕,调度器将该call从runningSyncCalls队列中移除
    15. client.dispatcher.finished(this)
    16. }
    17. }

    调度器调用executed犯法,将当前的RealCall对象加入到runningSyncCalls队列中,然后调用getResponseWithInterceptorChain方法拿到response。

    异步请求

    1. client.newCall(request).enqueue(object : Callback {
    2. override fun onFailure(call: Call, e: IOException) {
    3. e.printStackTrace()
    4. }
    5. override fun onResponse(call: Call, response: Response) {
    6. }
    7. })
    8. RealCall.kt
    9. override fun enqueue(responseCallback: Callback) {
    10. check(executed.compareAndSet(false, true)) { "Already Executed" }
    11. //开启请求监听
    12. callStart()
    13. //新建一个AsyncCall对象,通过调度器enqueue方法加入到readyAsyncCalls队列中
    14. client.dispatcher.enqueue(AsyncCall(responseCallback))
    15. }
    16. Dispatcher.kt
    17. internal fun enqueue(call: AsyncCall) {
    18. synchronized(this) {
    19. readyAsyncCalls.add(call)
    20. // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
    21. // the same host.
    22. if (!call.call.forWebSocket) {
    23. //通过域名来查找有没有相同域名的请求,有则复用
    24. val existingCall = findExistingCallWithHost(call.host)
    25. if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
    26. }
    27. }
    28. //执行请求
    29. promoteAndExecute()
    30. }
    31. private fun promoteAndExecute(): Boolean {
    32. this.assertThreadDoesntHoldLock()
    33. val executableCalls = mutableListOf()
    34. val isRunning: Boolean
    35. synchronized(this) {
    36. //遍历readyAsyncCalls队列
    37. val i = readyAsyncCalls.iterator()
    38. while (i.hasNext()) {
    39. val asyncCall = i.next()
    40. //检查runningAsyncCalls的数量
    41. if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
    42. //同域名最大请求数
    43. if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
    44. i.remove()
    45. asyncCall.callsPerHost.incrementAndGet()
    46. executableCalls.add(asyncCall)
    47. runningAsyncCalls.add(asyncCall)
    48. }
    49. isRunning = runningCallsCount() > 0
    50. }
    51. for (i in 0 until executableCalls.size) {
    52. val asyncCall = executableCalls[i]
    53. asyncCall.executeOn(executorService)
    54. }
    55. return isRunning
    56. }
    57. RealCall.kt
    58. fun executeOn(executorService: ExecutorService) {
    59. client.dispatcher.assertThreadDoesntHoldLock()
    60. var success = false
    61. try {
    62. //执行AsyncCall这个runnable
    63. executorService.execute(this)
    64. success = true
    65. } catch (e: RejectedExecutionException) {
    66. val ioException = InterruptedIOException("executor rejected")
    67. ioException.initCause(e)
    68. noMoreExchanges(ioException)
    69. responseCallback.onFailure(this@RealCall, ioException)
    70. } finally {
    71. if (!success) {
    72. client.dispatcher.finished(this) // This call is no longer running!
    73. }
    74. }
    75. }
    76. override fun run() {
    77. threadName("OkHttp ${redactedUrl()}") {
    78. var signalledCallback = false
    79. timeout.enter()
    80. try {
    81. //获取返回数据
    82. val response = getResponseWithInterceptorChain()
    83. signalledCallback = true
    84. responseCallback.onResponse(this@RealCall, response)
    85. } catch (e: IOException) {
    86. if (signalledCallback) {
    87. // Do not signal the callback twice!
    88. Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
    89. } else {
    90. responseCallback.onFailure(this@RealCall, e)
    91. }
    92. } catch (t: Throwable) {
    93. cancel()
    94. if (!signalledCallback) {
    95. val canceledException = IOException("canceled due to $t")
    96. canceledException.addSuppressed(t)
    97. responseCallback.onFailure(this@RealCall, canceledException)
    98. }
    99. throw t
    100. } finally {
    101. client.dispatcher.finished(this)
    102. }
    103. }
    104. }
    105. }

    获取Response

    1. @Throws(IOException::class)
    2. internal fun getResponseWithInterceptorChain(): Response {
    3. // Build a full stack of interceptors.
    4. //拦截器
    5. val interceptors = mutableListOf()
    6. interceptors += client.interceptors
    7. interceptors += RetryAndFollowUpInterceptor(client)
    8. interceptors += BridgeInterceptor(client.cookieJar)
    9. interceptors += CacheInterceptor(client.cache)
    10. interceptors += ConnectInterceptor
    11. if (!forWebSocket) {
    12. interceptors += client.networkInterceptors
    13. }
    14. interceptors += CallServerInterceptor(forWebSocket)
    15. //拦截器责任链
    16. val chain = RealInterceptorChain(
    17. call = this,
    18. interceptors = interceptors,
    19. index = 0,
    20. exchange = null,
    21. request = originalRequest,
    22. connectTimeoutMillis = client.connectTimeoutMillis,
    23. readTimeoutMillis = client.readTimeoutMillis,
    24. writeTimeoutMillis = client.writeTimeoutMillis
    25. )
    26. var calledNoMoreExchanges = false
    27. try {
    28. //根据拦截器责任链来获取response
    29. val response = chain.proceed(originalRequest)
    30. if (isCanceled()) {
    31. response.closeQuietly()
    32. throw IOException("Canceled")
    33. }
    34. return response
    35. } catch (e: IOException) {
    36. calledNoMoreExchanges = true
    37. throw noMoreExchanges(e) as Throwable
    38. } finally {
    39. if (!calledNoMoreExchanges) {
    40. noMoreExchanges(null)
    41. }
    42. }
    43. }
    44. RealInterceptorChain.kt
    45. @Throws(IOException::class)
    46. override fun proceed(request: Request): Response {
    47. check(index < interceptors.size)
    48. calls++
    49. if (exchange != null) {
    50. check(exchange.finder.sameHostAndPort(request.url)) {
    51. "network interceptor ${interceptors[index - 1]} must retain the same host and port"
    52. }
    53. check(calls == 1) {
    54. "network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
    55. }
    56. }
    57. // Call the next interceptor in the chain.
    58. //拷贝下一级责任链
    59. val next = copy(index = index + 1, request = request)
    60. val interceptor = interceptors[index]
    61. @Suppress("USELESS_ELVIS")
    62. //执行拦截器拦截方法
    63. val response = interceptor.intercept(next) ?: throw NullPointerException(
    64. "interceptor $interceptor returned null")
    65. if (exchange != null) {
    66. check(index + 1 >= interceptors.size || next.calls == 1) {
    67. "network interceptor $interceptor must call proceed() exactly once"
    68. }
    69. }
    70. check(response.body != null) { "interceptor $interceptor returned a response with no body" }
    71. return response
    72. }

    Interceptor

    该接口只声明了一个拦截器方法,同时,在其内部,还有一个Chain接口,核心方法是proceed(request)处理请求来获取response

    各类拦截器

    client.interceptors:由开发者自定义的拦截器,会在所有拦截器处理之前进行最早的拦截处理,可用于添加一些公共参数,如自定义header、自定义log等等。

    1. class HeadInterceptor : Interceptor {
    2. override fun intercept(chain: Interceptor.Chain): Response {
    3. val request = chain.request().newBuilder()
    4. .addHeader("device-serial", "********8")
    5. .build()
    6. return chain.proceed(request)
    7. }
    8. }
    9. fun test() {
    10. val client = OkHttpClient.Builder()
    11. .connectTimeout(60, TimeUnit.MILLISECONDS)
    12. .readTimeout(15, TimeUnit.MILLISECONDS)
    13. .writeTimeout(15, TimeUnit.MILLISECONDS)
    14. .addInterceptor(HeadInterceptor())
    15. .build()
    16. }

    RetryAndFollowUpInterceptor:这里会对连接做一些初始化的工作,以及请求失败的重试工作,重定向的后续请求工作。

    1. @Throws(IOException::class)
    2. override fun intercept(chain: Interceptor.Chain): Response {
    3. val realChain = chain as RealInterceptorChain
    4. var request = chain.request
    5. val call = realChain.call
    6. var followUpCount = 0
    7. var priorResponse: Response? = null
    8. var newExchangeFinder = true
    9. var recoveredFailures = listOf()
    10. while (true) {
    11. //这里创建一个exchangeFinder,ConnectInterceptor会用到
    12. call.enterNetworkInterceptorExchange(request, newExchangeFinder)
    13. var response: Response
    14. var closeActiveExchange = true
    15. try {
    16. if (call.isCanceled()) {
    17. throw IOException("Canceled")
    18. }
    19. try {
    20. response = realChain.proceed(request)
    21. newExchangeFinder = true
    22. } catch (e: RouteException) {
    23. // The attempt to connect via a route failed. The request will not have been sent.
    24. //当请求还未完全发送时连接失败,可以尝试检查是否能重新连接
    25. if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {
    26. throw e.firstConnectException.withSuppressed(recoveredFailures)
    27. } else {
    28. recoveredFailures += e.firstConnectException
    29. }
    30. newExchangeFinder = false
    31. continue
    32. } catch (e: IOException) {
    33. // An attempt to communicate with a server failed. The request may have been sent.
    34. if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
    35. throw e.withSuppressed(recoveredFailures)
    36. } else {
    37. recoveredFailures += e
    38. }
    39. newExchangeFinder = false
    40. continue
    41. }
    42. // Attach the prior response if it exists. Such responses never have a body.
    43. //尝试使用上一个已经构建好的response,body为空
    44. if (priorResponse != null) {
    45. response = response.newBuilder()
    46. .priorResponse(priorResponse.newBuilder()
    47. .body(null)
    48. .build())
    49. .build()
    50. }
    51. val exchange = call.interceptorScopedExchange
    52. //根据responseCode来判断,是否构建一个新的response并返回来重试或者重定向
    53. val followUp = followUpRequest(response, exchange)
    54. if (followUp == null) {
    55. if (exchange != null && exchange.isDuplex) {
    56. call.timeoutEarlyExit()
    57. }
    58. closeActiveExchange = false
    59. return response
    60. }
    61. val followUpBody = followUp.body
    62. if (followUpBody != null && followUpBody.isOneShot()) {
    63. closeActiveExchange = false
    64. return response
    65. }
    66. response.body?.closeQuietly()
    67. if (++followUpCount > MAX_FOLLOW_UPS) {
    68. throw ProtocolException("Too many follow-up requests: $followUpCount")
    69. }
    70. request = followUp
    71. priorResponse = response
    72. } finally {
    73. call.exitNetworkInterceptorExchange(closeActiveExchange)
    74. }
    75. }
    76. }
    77. /**
    78. * Report and attempt to recover from a failure to communicate with a server. Returns true if
    79. * `e` is recoverable, or false if the failure is permanent. Requests with a body can only
    80. * be recovered if the body is buffered or if the failure occurred before the request has been
    81. * sent.
    82. */
    83. //判断是否需要重连
    84. private fun recover(
    85. e: IOException,
    86. call: RealCall,
    87. userRequest: Request,
    88. requestSendStarted: Boolean
    89. ): Boolean {
    90. // The application layer has forbidden retries.
    91. //客户端禁止重试
    92. if (!client.retryOnConnectionFailure) return false
    93. //不能再次发送该请求体
    94. // We can't send the request body again.
    95. if (requestSendStarted && requestIsOneShot(e, userRequest)) return false
    96. //发生的异常时致命的,无法恢复
    97. // This exception is fatal.
    98. if (!isRecoverable(e, requestSendStarted)) return false
    99. //没有跟多的路由来尝试重连
    100. // No more routes to attempt.
    101. if (!call.retryAfterFailure()) return false
    102. // For failure recovery, use the same route selector with a new connection.
    103. return true
    104. }

    BridgeInterceptor:这是客户端与服务器之间的沟通桥梁,负责将用户构建的请求转换为服务器需要的请求,以及将网络请求返回回来的响应转换为用户可用的相应

    1. @Throws(IOException::class)
    2. override fun intercept(chain: Interceptor.Chain): Response {
    3. val userRequest = chain.request()
    4. val requestBuilder = userRequest.newBuilder()
    5. val body = userRequest.body
    6. if (body != null) {
    7. val contentType = body.contentType()
    8. if (contentType != null) {
    9. requestBuilder.header("Content-Type", contentType.toString())
    10. }
    11. val contentLength = body.contentLength()
    12. if (contentLength != -1L) {
    13. requestBuilder.header("Content-Length", contentLength.toString())
    14. requestBuilder.removeHeader("Transfer-Encoding")
    15. } else {
    16. requestBuilder.header("Transfer-Encoding", "chunked")
    17. requestBuilder.removeHeader("Content-Length")
    18. }
    19. }
    20. if (userRequest.header("Host") == null) {
    21. requestBuilder.header("Host", userRequest.url.toHostHeader())
    22. }
    23. if (userRequest.header("Connection") == null) {
    24. requestBuilder.header("Connection", "Keep-Alive")
    25. }
    26. // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    27. // the transfer stream.
    28. var transparentGzip = false
    29. if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
    30. transparentGzip = true
    31. requestBuilder.header("Accept-Encoding", "gzip")
    32. }
    33. val cookies = cookieJar.loadForRequest(userRequest.url)
    34. if (cookies.isNotEmpty()) {
    35. requestBuilder.header("Cookie", cookieHeader(cookies))
    36. }
    37. if (userRequest.header("User-Agent") == null) {
    38. requestBuilder.header("User-Agent", userAgent)
    39. }
    40. //执行下一个拦截器
    41. val networkResponse = chain.proceed(requestBuilder.build())
    42. cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)
    43. val responseBuilder = networkResponse.newBuilder()
    44. .request(userRequest)
    45. if (transparentGzip &&
    46. "gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
    47. networkResponse.promisesBody()) {
    48. val responseBody = networkResponse.body
    49. if (responseBody != null) {
    50. val gzipSource = GzipSource(responseBody.source())
    51. val strippedHeaders = networkResponse.headers.newBuilder()
    52. .removeAll("Content-Encoding")
    53. .removeAll("Content-Length")
    54. .build()
    55. responseBuilder.headers(strippedHeaders)
    56. val contentType = networkResponse.header("Content-Type")
    57. responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))
    58. }
    59. }
    60. return responseBuilder.build()
    61. }

    CacheInterceptor:这里是缓存相关的处理,会根据用户在OkhttpClient里定义的缓存配置,然后结合请求新建一个缓存策略,由他来判断使用网络还是缓存来构建response

    1. @Throws(IOException::class)
    2. override fun intercept(chain: Interceptor.Chain): Response {
    3. val call = chain.call()
    4. val cacheCandidate = cache?.get(chain.request())
    5. val now = System.currentTimeMillis()
    6. //创建一个缓存策略
    7. val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()
    8. //使用网络
    9. val networkRequest = strategy.networkRequest
    10. //使用缓存
    11. val cacheResponse = strategy.cacheResponse
    12. //追踪网络与缓存的使用情况
    13. cache?.trackResponse(strategy)
    14. val listener = (call as? RealCall)?.eventListener ?: EventListener.NONE
    15. //关闭不适用的缓存数据
    16. if (cacheCandidate != null && cacheResponse == null) {
    17. // The cache candidate wasn't applicable. Close it.
    18. cacheCandidate.body?.closeQuietly()
    19. }
    20. //如果网络被禁止,同时缓存也是空的,构建一个code为504的response返回
    21. // If we're forbidden from using the network and the cache is insufficient, fail.
    22. if (networkRequest == null && cacheResponse == null) {
    23. return Response.Builder()
    24. .request(chain.request())
    25. .protocol(Protocol.HTTP_1_1)
    26. .code(HTTP_GATEWAY_TIMEOUT)
    27. .message("Unsatisfiable Request (only-if-cached)")
    28. .body(EMPTY_RESPONSE)
    29. .sentRequestAtMillis(-1L)
    30. .receivedResponseAtMillis(System.currentTimeMillis())
    31. .build().also {
    32. listener.satisfactionFailure(call, it)
    33. }
    34. }
    35. //没有网络,由缓存数据,则构建缓存内容并返回
    36. // If we don't need the network, we're done.
    37. if (networkRequest == null) {
    38. return cacheResponse!!.newBuilder()
    39. .cacheResponse(stripBody(cacheResponse))
    40. .build().also {
    41. listener.cacheHit(call, it)
    42. }
    43. }
    44. if (cacheResponse != null) {
    45. listener.cacheConditionalHit(call, cacheResponse)
    46. } else if (cache != null) {
    47. listener.cacheMiss(call)
    48. }
    49. var networkResponse: Response? = null
    50. try {
    51. networkResponse = chain.proceed(networkRequest)
    52. } finally {
    53. // If we're crashing on I/O or otherwise, don't leak the cache body.
    54. if (networkResponse == null && cacheCandidate != null) {
    55. cacheCandidate.body?.closeQuietly()
    56. }
    57. }
    58. // If we have a cache response too, then we're doing a conditional get.
    59. if (cacheResponse != null) {
    60. //如果由缓存,且返回的code为304时,使用缓存构建数据并返回
    61. if (networkResponse?.code == HTTP_NOT_MODIFIED) {
    62. val response = cacheResponse.newBuilder()
    63. .headers(combine(cacheResponse.headers, networkResponse.headers))
    64. .sentRequestAtMillis(networkResponse.sentRequestAtMillis)
    65. .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis)
    66. .cacheResponse(stripBody(cacheResponse))
    67. .networkResponse(stripBody(networkResponse))
    68. .build()
    69. networkResponse.body!!.close()
    70. // Update the cache after combining headers but before stripping the
    71. // Content-Encoding header (as performed by initContentStream()).
    72. cache!!.trackConditionalCacheHit()
    73. cache.update(cacheResponse, response)
    74. return response.also {
    75. listener.cacheHit(call, it)
    76. }
    77. } else {
    78. cacheResponse.body?.closeQuietly()
    79. }
    80. }
    81. val response = networkResponse!!.newBuilder()
    82. .cacheResponse(stripBody(cacheResponse))
    83. .networkResponse(stripBody(networkResponse))
    84. .build()
    85. if (cache != null) {
    86. if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {
    87. // Offer this request to the cache.
    88. val cacheRequest = cache.put(response)
    89. return cacheWritingResponse(cacheRequest, response).also {
    90. if (cacheResponse != null) {
    91. // This will log a conditional cache miss only.
    92. listener.cacheMiss(call)
    93. }
    94. }
    95. }
    96. //根据请求方法来判定缓存是否有效,只对Get请求进行缓存
    97. if (HttpMethod.invalidatesCache(networkRequest.method)) {
    98. try {
    99. cache.remove(networkRequest)
    100. } catch (_: IOException) {
    101. // The cache cannot be written.
    102. }
    103. }
    104. }
    105. return response
    106. }

    ConnectInterceptor:这里主要是负责建立连接,会建立tcp或者tls连接

    1. @Throws(IOException::class)
    2. override fun intercept(chain: Interceptor.Chain): Response {
    3. val realChain = chain as RealInterceptorChain
    4. val exchange = realChain.call.initExchange(chain)
    5. val connectedChain = realChain.copy(exchange = exchange)
    6. return connectedChain.proceed(realChain.request)
    7. }

    client.networkInterceptors:这也是开发者自己设置的,但所处位置不同,用处也不相同

    CallServerInterceptor:这里是进行网络请求和响应的地方。将请求头与请求体发送给服务器,以及解析服务器返回的response。

    以下是整体调用流程

    知识点:

    建造者模式:不论是OkHttpClient、Request还是Response,都是用了建造者模式,因为这几个类中都有很多参数,需要供用户选择需要的参数来构建其想要的实例。

    工厂方法模式:帮助生成复杂对象,比如OkHttpClient.newCall(request Request)来创建call对象

    责任链模式:这里将拦截器构建成拦截器责任链,然后按顺序从上往下执行,得到response后,从下往上传。

    线程安全

    使用原子类,重入锁等实现线程安全

    数据结构

    采用队列实现,更符合整体网络请求的要求,比如先到先得。

  • 相关阅读:
    AndroidStudio 导入项目模块失败
    Java多线程学习入门(六):锁升级、锁消除、锁粗化
    JS基本数据类型中null和undefined区别及应用
    oracle的使用sqlplush
    Elasticsearch:ES|QL 查询 TypeScript 类型(二)
    实施MES管理系统前,这三个问题要考虑好
    01贪心:算法理论知识
    MP简单的分页查询测试
    如何在邮箱客户端上设置配置使用多个邮箱
    笔记本电脑的摄像头找不到黑屏解决办法
  • 原文地址:https://blog.csdn.net/Dragonlongbo/article/details/136977367