okhttp 脱离了Android很早之前的HttpUrlConnection,全部重写,目前已经被Android官方进行收录,是公认的最佳方案。

在这之前,需要了解网络基础、加密与解密、HTTP/HTTPS 以及TCP/IP的原理,你才能真正的读懂OkHttp.

网络 | 你必须会的网络基础
网络 | TCP/IP 协议族
网络 | HTTPS 原理

在之前我写过一篇OkHttp的设计思想,详细讲解了OKhttp的责任链模式,以及执行流程。之前讲的不是很清楚,既然本文章是OkHttp全解析,肯定是要详细讲解,所以本文会重新讲解一遍从0到1. 本文采用线路图的思路去解析源码(在之前写的Retrofit 全面解析 就是采用线路图的方式,这也是我推荐的一种阅读源码的方式)

OkHttp的官方地址:https://square.github.io/okhttp/,okhttp的使用不需要在多说了吧,直接看官方文档即可。
当前使用的版本:implementation 'com.squareup.okhttp3:okhttp:4.9.1'

  1. val client = OkHttpClient.Builder().build()
  2. val request = Request.Builder()
  3. .url("https://api.github.com/users/octocat/repos")
  4. .build()
  5. client.newCall(request).enqueue(object :okhttp3.Callback{
  6. override fun onFailure(call: okhttp3.Call, e: IOException) {
  7. TODO("Not yet implemented")
  8. }
  9. override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {
  10. println(response.body.toString())
  11. }
  12. })

下面我们先分析OkHttp的执行流程。

执行流程

在上述的代码中,OkHttp开始执行请求是调用了newCall方法,request是请求的一些配置信息。

  1. override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

newCall返回了RealCall的对象,并将Request实例作为参数传递,显然RealCall必然实现了Call接口。下面有了两天线路,先看线路1RealCall做了什么
image.png

线路1:RealCall

代码如下:RealCall果然实现了Call接口,构造函数中有几个参数,一个是OkHttpClient,Request以及forWebSocket(forWebSocket默认是FALSE,通过WebSocket进行通信,一般一些股票的APP会用到实时刷新等功能)。

  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 // 频繁刷新数据,一般不会使用,例如:股票实时刷新等功能 通过webSocket
  6. ) : Call

从Call的接口可以看出RealCall主要实现了几个方法,最主要:execute(同步执行网络请求)、enqueue(异步执行网络请求)、cancel(取消网络请求)

  1. interface Call : Cloneable {
  2. fun request(): Request
  3. @Throws(IOException::class)
  4. fun execute(): Response
  5. fun enqueue(responseCallback: Callback)
  6. fun cancel()
  7. fun isExecuted(): Boolean
  8. fun isCanceled(): Boolean
  9. fun timeout(): Timeout
  10. public override fun clone(): Call
  11. fun interface Factory {
  12. fun newCall(request: Request): Call
  13. }
  14. }

我们继续看线路图:多了三条主要的线路,按照线路图阅读源码的思路,只看一条线路,首先看线路3 enqueue的异步网络请求的实现。
image.png

线路3 enqueue

Dispatcher 负责线程调度,通过ExecutorService负责线程管理

  1. maxRequests = 64 最大的同时请求进行,如果超过这个数,后面的请求需要进行等待
  2. maxRequestsPerHost = 5 主机的最大的同时请求数据

代码如下:其实就做了一件事,调用Dispathcher的enqueue方法

  1. override fun enqueue(responseCallback: Callback) {
  2. .....
  3. client.dispatcher.enqueue(AsyncCall(responseCallback))
  4. }

AsyncCallRealCall的内部类,实现了Runnable接口,作为线程的执行类

Dispatcher做线程调度的,内部维护了一个线程池多个线程管理,在后台线程执行网络请求,其实就是执行AsyncCall

  1. internal fun enqueue(call: AsyncCall) {
  2. synchronized(this) {
  3. // 将准备要执行的call,放入准备队列中,准备执行
  4. readyAsyncCalls.add(call)
  5. //记录perHost主机数
  6. if (!call.call.forWebSocket) {
  7. val existingCall = findExistingCallWithHost(call.host)
  8. if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
  9. }
  10. }
  11. //执行
  12. promoteAndExecute()
  13. }

readyAsyncCalls -> ArrayDeque 存储准备要执行但是还没有执行的请求,包括请求达到了maxRequest或者maxRequestPerHost的请求也会加入这个队列中去。promoteAndExecute去执行请求

findExistingCallWithHost去找到目前正在执行的请求或者准备的请求是否存在当前请求的host,这里代码比较简单,直接遍历队列即可

  1. private fun findExistingCallWithHost(host: String): AsyncCall? {
  2. for (existingCall in runningAsyncCalls) {
  3. if (existingCall.host == host) return existingCall
  4. }
  5. for (existingCall in readyAsyncCalls) {
  6. if (existingCall.host == host) return existingCall
  7. }
  8. return null
  9. }

当findExistingCallWithHost存在和当前请求相同的主机名host时,调用当前请求的AsyncCall中的reuseCallsPerHostFrom方法,并且传入目前存在的AsyncCall的实例,其实每次执行请求,都会在AsyncCall中存储一个变量callsPerHost记录当前请求host的数量,去同步当前的请求的host的数量.

  1. @Volatile var callsPerHost = AtomicInteger(0)
  2. private set
  3. fun reuseCallsPerHostFrom(other: AsyncCall) {
  4. this.callsPerHost = other.callsPerHost
  5. }

在通过执行AsyncCall的请求的时候,也就是通过promoteAndExecutecallsPerHost进行加1

  1. asyncCall.callsPerHost.incrementAndGet()

这里记录同时请求主机数的设计非常巧妙,通过遍历正在执行或者准备执行的AsyncCall队列,并且每个AsyncCall都会有一个callsPerHost进行共享,在调用promoteAndExecute执行请求的时候进行+1,当某个请求完成后执行Dispatcher.finished(call)方法,decrementAndGet -1 操作,并且从runningAsyncCalls移除call,这里的call的移除一定要线程安全的通过synchronized进行线程锁定

  1. internal fun finished(call: AsyncCall) {
  2. call.callsPerHost.decrementAndGet()
  3. finished(runningAsyncCalls, call)
  4. }
  5. private fun <T> finished(calls: Deque<T>, call: T) {
  6. val idleCallback: Runnable?
  7. synchronized(this) {
  8. if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
  9. idleCallback = this.idleCallback
  10. }
  11. //idleCallback 其实和Handler中的idelHandler类似,空闲执行的操作,当所有的网络请求执行完毕了,执行idleCallback的操作
  12. //promoteAndExecute 执行下一个请求
  13. val isRunning = promoteAndExecute()
  14. if (!isRunning && idleCallback != null) {
  15. idleCallback.run()
  16. }
  17. }

执行逻辑如下:promoteAndExecute主要做了两件事,一个promote 符合条件的推举:是判断请求/主机的最大数,另一个就是Execute开启后台线程执行网络请求

  1. private fun promoteAndExecute(): Boolean {
  2. .....
  3. // 维护一个执行的列表
  4. val executableCalls = mutableListOf<AsyncCall>()
  5. // 标记是否正在运行
  6. val isRunning: Boolean
  7. synchronized(this) {
  8. // 从准备队列中获取Call
  9. val i = readyAsyncCalls.iterator()
  10. while (i.hasNext()) {
  11. val asyncCall = i.next()
  12. // 判断运行中的Call是否超出了最大请求值,因为网络请求可能多个请求
  13. if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
  14. // 判断请求的host是否超过最大请求
  15. if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
  16. i.remove()
  17. asyncCall.callsPerHost.incrementAndGet()
  18. // 将call添加到正在执行的列表中
  19. executableCalls.add(asyncCall)
  20. // 添加到运行中的队列中
  21. runningAsyncCalls.add(asyncCall)
  22. }
  23. isRunning = runningCallsCount() > 0
  24. }
  25. // 遍历正在执行的列表,在Dispatcher提供的线程池中执行网络请求
  26. for (i in 0 until executableCalls.size) {
  27. val asyncCall = executableCalls[i]
  28. //传递线程
  29. asyncCall.executeOn(executorService)
  30. }
  31. return isRunning
  32. }

asyncCall.executeOn 就是执行线程:

  1. fun executeOn(executorService: ExecutorService) {
  2. client.dispatcher.assertThreadDoesntHoldLock()
  3. var success = false
  4. try {
  5. //执行线程 - runnable
  6. executorService.execute(this)
  7. ....
  8. }
  9. }

AsyncCall

网络请求,最终会回到AsyncCall中执行线程,在run方法中主要通过getResponseWithInterceptorChain执行网络请求,拿到响应。这是OkHttp的核心,内部实现了网络的真正的请求

  1. override fun run() {
  2. threadName("OkHttp ${redactedUrl()}") {
  3. .....
  4. try {
  5. val response = getResponseWithInterceptorChain()
  6. signalledCallback = true
  7. responseCallback.onResponse(this@RealCall, response)
  8. }finally {
  9. //执行完毕 处理完成逻辑
  10. client.dispatcher.finished(this)
  11. }
  12. }
  13. ...
  14. }

配置参数详解

百度上有很多解释,这里简单介绍一下:

  1. // 线程调度器
  2. @get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher
  3. // 连接池 内存存储一批的连接,复用连接
  4. @get:JvmName("connectionPool") val connectionPool: ConnectionPool = builder.connectionPool
  5. // 拦截器
  6. @get:JvmName("interceptors") val interceptors: List<Interceptor> =
  7. builder.interceptors.toImmutableList()
  8. @get:JvmName("networkInterceptors") val networkInterceptors: List<Interceptor> =
  9. builder.networkInterceptors.toImmutableList()
  10. // EventListener 工厂 对请求过程的监听器
  11. @get:JvmName("eventListenerFactory") val eventListenerFactory: EventListener.Factory =
  12. builder.eventListenerFactory
  13. // 在链接/请求失败的时候是否重试 默认开启
  14. @get:JvmName("retryOnConnectionFailure") val retryOnConnectionFailure: Boolean =
  15. builder.retryOnConnectionFailure
  16. // 服务器认证
  17. @get:JvmName("authenticator") val authenticator: Authenticator = builder.authenticator
  18. // 一般我们可以通过这样去操作
  19. val client = OkHttpClient.Builder()
  20. .authenticator(object :Authenticator{
  21. override fun authenticate(route: Route?, response: okhttp3.Response): Request? {
  22. //.......把token进行刷新刷新
  23. return response.request.newBuilder()
  24. .header("Authorization","Bearer xxxx")
  25. .build()
  26. }
  27. }).build()
  28. // 是否重定向 默认打开 服务器要求重定向的时候是否要重定向
  29. @get:JvmName("followRedirects") val followRedirects: Boolean = builder.followRedirects
  30. // 协议切换 http -> https(Ssl) 切换是否需要重定向 默认打开
  31. @get:JvmName("followSslRedirects") val followSslRedirects: Boolean = builder.followSslRedirects
  32. // 饼干罐子 存储cookie,默认OkHttp是没有实现的,如果用到自己实现即可
  33. @get:JvmName("cookieJar") val cookieJar: CookieJar = builder.cookieJar
  34. // 缓存
  35. @get:JvmName("cache") val cache: Cache? = builder.cache
  36. // DNS 域名 :把域名解析为IP地址
  37. @get:JvmName("dns") val dns: Dns = builder.dns
  38. // Proxy 代理 默认是直连
  39. @get:JvmName("proxy") val proxy: Proxy? = builder.proxy
  40. // 选择代理 默认是直连NullProxySelector
  41. @get:JvmName("proxySelector") val proxySelector: ProxySelector =
  42. when {
  43. // Defer calls to ProxySelector.getDefault() because it can throw a SecurityException.
  44. builder.proxy != null -> NullProxySelector
  45. else -> builder.proxySelector ?: ProxySelector.getDefault() ?: NullProxySelector
  46. }
  47. // 代理认证授权
  48. @get:JvmName("proxyAuthenticator") val proxyAuthenticator: Authenticator =
  49. builder.proxyAuthenticator
  50. // socketFactory socket工厂 创建Socket
  51. @get:JvmName("socketFactory") val socketFactory: SocketFactory = builder.socketFactory
  52. // tcp 加密连接 SSLSocketFactory,在TCP上面加上TSL也是SSL加密
  53. private val sslSocketFactoryOrNull: SSLSocketFactory?
  54. @get:JvmName("sslSocketFactory") val sslSocketFactory: SSLSocketFactory
  55. get() = sslSocketFactoryOrNull ?: throw IllegalStateException("CLEARTEXT-only client")
  56. //x509TrustManager 证书的验证器
  57. @get:JvmName("x509TrustManager") val x509TrustManager: X509TrustManager?
  58. // 连接标准/规范 加密和解密 加密套件、算法
  59. @get:JvmName("connectionSpecs") val connectionSpecs: List<ConnectionSpec> =
  60. builder.connectionSpecs
  61. // 支持的哪些协议 如:http/1.0 http/1.1 http/2 等等
  62. @get:JvmName("protocols") val protocols: List<Protocol> = builder.protocols
  63. // 证书验证相关 :hostname 验证
  64. @get:JvmName("hostnameVerifier") val hostnameVerifier: HostnameVerifier = builder.hostnameVerifier
  65. // 证书验证相关:订证书
  66. @get:JvmName("certificatePinner") val certificatePinner: CertificatePinner
  67. // 证书验证相关:操作X509TrustManager 去验证证书的合法性
  68. @get:JvmName("certificateChainCleaner") val certificateChainCleaner: CertificateChainCleaner?
  69. /**
  70. * Default call timeout (in milliseconds). By default there is no timeout for complete calls, but
  71. * there is for the connect, write, and read actions within a call.
  72. */
  73. @get:JvmName("callTimeoutMillis") val callTimeoutMillis: Int = builder.callTimeout
  74. /** Default connect timeout (in milliseconds). The default is 10 seconds. */
  75. @get:JvmName("connectTimeoutMillis") val connectTimeoutMillis: Int = builder.connectTimeout
  76. /** Default read timeout (in milliseconds). The default is 10 seconds. */
  77. @get:JvmName("readTimeoutMillis") val readTimeoutMillis: Int = builder.readTimeout
  78. /** Default write timeout (in milliseconds). The default is 10 seconds. */
  79. @get:JvmName("writeTimeoutMillis") val writeTimeoutMillis: Int = builder.writeTimeout
  80. /** Web socket and HTTP/2 ping interval (in milliseconds). By default pings are not sent. */
  81. // 心跳间隔
  82. @get:JvmName("pingIntervalMillis") val pingIntervalMillis: Int = builder.pingInterval

连接池的复用:

在HTTP1 当这个连接用完了,下一个连接会进行复用。 在HTTP2 中支持多路复用,哪怕这个连接正在使用,也可以进行复用。

okhttp如何发送请求和获取响应

getResponseWithInterceptorChain 除了最后一个Interceptor 其他的Interceptor都会有前置、中置、后置的工作

image.png
下面分析每一个Interceptor的做了什么:

  1. //1 拦截器列表
  2. val interceptors = mutableListOf<Interceptor>()
  3. interceptors += client.interceptors
  4. interceptors += RetryAndFollowUpInterceptor(client)
  5. interceptors += BridgeInterceptor(client.cookieJar)
  6. interceptors += CacheInterceptor(client.cache)
  7. interceptors += ConnectInterceptor
  8. if (!forWebSocket) {
  9. interceptors += client.networkInterceptors
  10. }
  11. interceptors += CallServerInterceptor(forWebSocket)
  12. //2 拦截器组成链条
  13. val chain = RealInterceptorChain(
  14. call = this,
  15. interceptors = interceptors,
  16. index = 0,
  17. exchange = null,
  18. request = originalRequest,
  19. connectTimeoutMillis = client.connectTimeoutMillis,
  20. readTimeoutMillis = client.readTimeoutMillis,
  21. writeTimeoutMillis = client.writeTimeoutMillis
  22. )
  23. //3 让链条转起来
  24. val response = chain.proceed(originalRequest)

procced 是让链条转起来的关键方法:interceptor.intercept会执行当前拦截器的前置工作,然后中置工作会调用next.proceed,由于next创建的Chain对象,index = index+1,所以Interceptor会拿到下一个拦截器,然后执行前置工作,中置工作同样也会调用next.proceed继续执行下一个拦截器,知道最后一个拦截器返回,前面的拦截器执行后置工作。

  1. override fun proceed(request: Request): Response {
  2. ......
  3. // Call the next interceptor in the chain.
  4. val next = copy(index = index + 1, request = request)
  5. val interceptor = interceptors[index]
  6. @Suppress("USELESS_ELVIS")
  7. val response = interceptor.intercept(next) ?: throw NullPointerException(
  8. "interceptor $interceptor returned null")
  9. ......
  10. return response
  11. }

网络 | OkHttp 全解析 - 图4

责任链的实现代码模型如下:

  1. interface Interceptor {
  2. fun interceptor(china: China): String
  3. interface China {
  4. fun proceed(): String
  5. }
  6. }

创建责任链:RealInterceptorChina

  1. class RealInterceptorChina(val index: Int = 0, val interceptors: List<Interceptor>) :
  2. Interceptor.China {
  3. private fun copy(
  4. index: Int = this.index,
  5. interceptors: List<Interceptor> = this.interceptors
  6. ): Interceptor.China {
  7. return RealInterceptorChina(index, interceptors)
  8. }
  9. override fun proceed(): String {
  10. //获取下一个Interceptor,copy之后 下一个next中的China对象 index = index+1
  11. val next = copy(index + 1, interceptors)
  12. val interceptor = interceptors[index]
  13. //将有下一个拦截器的China对象传入
  14. return interceptor.interceptor(next)
  15. }
  16. }
  1. private fun testInterceptor() {
  2. val list = mutableListOf<Interceptor>()
  3. list.add(object : Interceptor {
  4. override fun interceptor(china: Interceptor.China): String {
  5. Log.e("TAG", "interceptor1: 前置工作")
  6. val result = china.proceed()
  7. Log.e("TAG", "interceptor1: 后置工作 -> $result ")
  8. return result
  9. }
  10. })
  11. list.add(object : Interceptor {
  12. override fun interceptor(china: Interceptor.China): String {
  13. Log.e("TAG", "interceptor2: 前置工作")
  14. val result = china.proceed()
  15. Log.e("TAG", "interceptor2: 后置工作 -> $result ")
  16. return result
  17. }
  18. })
  19. list.add(object : Interceptor {
  20. override fun interceptor(china: Interceptor.China): String {
  21. Log.e("TAG", "interceptor3: 最后一个拦截器直接返回")
  22. return "Hello China"
  23. }
  24. })
  25. val china = RealInterceptorChina(0,list)
  26. val result = china.proceed()
  27. Log.e("TAG", "testInterceptor: $result")
  28. }

RetryAndFollowUpInterceptor

错误重试或重定向拦截器,RetryAndFollowUpInterceptor的主要作用:

  1. 前置:准备一个 的连接
  2. 后置:捕捉异常,进行错误重试或者有重定向的进行重定向,整个拦截器是一个while(true)的循环,直到没有错误或重定向return response

前置工作:准备一个可用的连接

  1. call.enterNetworkInterceptorExchange(request, newExchangeFinder)

ExchangeFinder寻找一次数据交换,寻找一个可用的连接,做一个准备工作,在其他的Interceptor进行使用,调用的RealCall中的enterNetworkInterceptorExchange方法,主要是从连接池connectionPool中寻找一个可用的连接,存储在RealCallexchaneFinder变量中,提供其他拦截器的使用。

  1. fun enterNetworkInterceptorExchange(request: Request, newExchangeFinder: Boolean) {
  2. ........
  3. if (newExchangeFinder) {
  4. this.exchangeFinder = ExchangeFinder(
  5. connectionPool,
  6. createAddress(request.url),
  7. this,
  8. eventListener
  9. )
  10. }
  11. }

后置工作:重试和重定向,RetryAndFollowUpInterceptor 将所有的工作写在while(true)循环中,只要出现在规定的错误或者重定向,都会重新走一次循环,直到正确返回结果或者抛出异常才会终止死循环。

  1. while (true) {
  2. call.enterNetworkInterceptorExchange(request, newExchangeFinder)
  3. try {
  4. response = realChain.proceed(request)
  5. newExchangeFinder = true
  6. } catch (e: RouteException) {
  7. if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {
  8. throw e.firstConnectException.withSuppressed(recoveredFailures)
  9. } else {
  10. recoveredFailures += e.firstConnectException
  11. }
  12. newExchangeFinder = false
  13. continue
  14. } catch (e: IOException) {
  15. if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
  16. throw e.withSuppressed(recoveredFailures)
  17. } else {
  18. recoveredFailures += e
  19. }
  20. newExchangeFinder = false
  21. continue
  22. }
  23. }

上述代码看着比较多,但是核心代码就几行:查找异常如果不存在规定的异常则抛出,否则循环重新请求一遍。

  1. if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {
  2. throw e.firstConnectException.withSuppressed(recoveredFailures)
  3. } else {
  4. recoveredFailures += e.firstConnectException
  5. }
  6. continue //重走循环

recover的实现如下:非常清晰的设置了那些状态下可以重试

  1. private fun recover(
  2. e: IOException,
  3. call: RealCall,
  4. userRequest: Request,
  5. requestSendStarted: Boolean
  6. ): Boolean {
  7. // OkHttpClient 是否开启了失败重试,默认开启
  8. if (!client.retryOnConnectionFailure) return false
  9. // We can't send the request body again.
  10. if (requestSendStarted && requestIsOneShot(e, userRequest)) return false
  11. // This exception is fatal. 如果存在某些异常则不重试
  12. if (!isRecoverable(e, requestSendStarted)) return false
  13. // No more routes to attempt.
  14. if (!call.retryAfterFailure()) return false
  15. // For failure recovery, use the same route selector with a new connection.
  16. return true
  17. }

下面在看重定向的机制实现:通过followUpRequest方法,去查找是否存在重定向的请求,如果followUp不为空,表示存在重定向的请求,将followUp赋值给request继续循环,使用followUp进行重新请求。

  1. val exchange = call.interceptorScopedExchange
  2. val followUp = followUpRequest(response, exchange)
  3. if (followUp == null) {
  4. if (exchange != null && exchange.isDuplex) {
  5. call.timeoutEarlyExit()
  6. }
  7. closeActiveExchange = false
  8. return response
  9. }
  10. val followUpBody = followUp.body
  11. //isOneShot=true 表示这个连接只有一次机会,不会进行重定向 直接return
  12. if (followUpBody != null && followUpBody.isOneShot()) {
  13. closeActiveExchange = false
  14. return response
  15. }
  16. response.body?.closeQuietly()
  17. .......
  18. request = followUp //下次请求使用的是followUp的重定向的请求
  19. priorResponse = response

followUpRequest的实现其实也很简单,需要用到前面学习的HTTP知识: 这里我只列出了核心的代码块 其实主要就是判断返回的responseresponseCode判断是否需要重定向:这个返回其实就是返回了一个新的Request对象,重新请求。

  1. HTTP_PROXY_AUTH -> { //407 表示设置了代理 需要代理服务器进行重定向到指定的IP
  2. val selectedProxy = route!!.proxy
  3. if (selectedProxy.type() != Proxy.Type.HTTP) {
  4. throw ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy")
  5. }
  6. return client.proxyAuthenticator.authenticate(route, userResponse)
  7. }
  8. // 401 未授权,这里在OkHttpClient的配置参数讲过authenticator 需要你重新配置request 然后再重新请求。。。。原来在这里这样使用啊
  9. HTTP_UNAUTHORIZED -> return client.authenticator.authenticate(route, userResponse)
  10. //3xx 剩下的就都是重定向的错误了
  11. HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> {
  12. return buildRedirectRequest(userResponse, method)
  13. }

关于RetryAndFollowUpInterceptor前置工作和后置工作就全部清晰了,RetryAndFollowUpInterceptor通过前置工作准备一个可用的连接存储到RealCall.exchangeFinder变量中,供后续的拦截器使用,后置工作首先会捕捉请求异常,如果存在OkHttp可以重试的异常则continue重新请求,如果不存在则抛出异常。当没有请求异常时,会通过followUpRequest去判断是否存在重定向,如果返回的followUp不为空并且不是一个坏的连接则对followUp进行重新请求。

BridgeInterceptor

BridgeInterceptor 拦截器主要作用就是帮助开发者补充Header信息,以及解压gzip的压缩数据

BridgeInterceptor 拦截器的前置工作:补齐Header信息,OkHttp请求只需要我们传入一个URL,其他的OkHttp通过BridgeInterceptor 帮助我们都完成了。

  1. POST /user/api HTTP 1.1
  2. Content-Type : xxxx
  3. Content-Length : ????
  4. body.......

比较有趣的是,BridgeInterceptor 帮助我们开启了gzip的数据压缩, 这里默认就开启了,因为数据的压缩有利于网络的传输。

  1. var transparentGzip = false
  2. if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
  3. transparentGzip = true
  4. requestBuilder.header("Accept-Encoding", "gzip")
  5. }

在BridgeInterceptor 的后置工作主要就是解压gzip数据,也就是说OKHttp帮助我们完成了gzip的解压工作,不需要开发人员进行处理,so :OkHttp 帮助我们完成了很多工作

GzipSource 是okio实现的,okio后续在详细的讲解。

  1. val networkResponse = chain.proceed(requestBuilder.build()) //执行下一个拦截器 拿到返回结果
  2. cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)
  3. val responseBuilder = networkResponse.newBuilder()
  4. .request(userRequest)
  5. //将返回的压缩数据进行解压
  6. if (transparentGzip &&
  7. "gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
  8. networkResponse.promisesBody()) {
  9. val responseBody = networkResponse.body
  10. if (responseBody != null) {
  11. val gzipSource = GzipSource(responseBody.source())
  12. val strippedHeaders = networkResponse.headers.newBuilder()
  13. .removeAll("Content-Encoding")
  14. .removeAll("Content-Length")
  15. .build()
  16. responseBuilder.headers(strippedHeaders)
  17. val contentType = networkResponse.header("Content-Type")
  18. responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))
  19. }
  20. }

整个BridgeInterceptor 的工作还是比较简单的:前置工作补齐Header内容开启gzip,后置工作主要是解压gzip的压缩数据。

CacheInterceptor

前置工作:请求之前有可用缓存就是用缓存,后置工作:如果请求的结果可以缓存就缓存下来