美文网首页
okhttp 请求过程源码分析

okhttp 请求过程源码分析

作者: 我爱田Hebe | 来源:发表于2022-03-17 22:18 被阅读0次

    本篇基于 okhttp 4.9.3 进行分析学习。

    okhttp 项目地址

    前言

    Android 项目开发中离不开网络请求,说到网络请求一定会想到 okhttp。

    okhttp 是如何完成一次请求的呢,接下来我们一步步来分析。

    首先看下完整的流程图,此处直接使用 Piasy 大佬的图

    一、如何发起请求

    1. Android 工程中使用配置

    添加网络请求权限 <uses-permission android:name="android.permission.INTERNET"/>

    添加依赖 implementation "com.squareup.okhttp3:okhttp:4.9.3"

    2. 发起请求

    以发送 GET 请求为例,其他类型请求也是通过在创建 requst 对象时进行设置。

    // 创建 OkHttpClient 实例对象,设置了超时时间
    val client = OkHttpClient.Builder()
        .callTimeout(10, TimeUnit.SECONDS)
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .build()
    
    // 创建 requset 对象,设置 url、请求方式、header 等信息
    val request = Request.Builder().url(url).build()
    
    // 同步执行,需放到子线程中执行
    GlobalScope.launch(Dispatchers.IO) {
        val response = client.newCall(request).execute().body?.string()
    }
    
    // 异步执行
    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            Log.d(TAG, e.message ?: "have IOException")
        }
    
        override fun onResponse(call: Call, response: Response) {
            val response = response.body?.string()
            Log.d(TAG, "enqueue() response = $response")
        }
    })
    
    
    

    二、发起一次请求都经历了什么

    分析上面 GET 请求时用到的对象,源码只保留流程中重要的部分。

    1. OkHttpClient

    open class OkHttpClient internal constructor(
      builder: Builder
    ) : Cloneable, Call.Factory, WebSocket.Factory {
    
        ...
        
        // OkHttpClient 可以构建 Call 的原因,因为实现了 Call.Factory
        override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
    
        ...
    
        // 默认构建参数
        class Builder constructor() {
          internal var dispatcher: Dispatcher = Dispatcher() // 调度器
          internal var connectionPool: ConnectionPool = ConnectionPool() // 连接池
          internal val interceptors: MutableList<Interceptor> = mutableListOf() // 拦截器
          internal val networkInterceptors: MutableList<Interceptor> = mutableListOf() // 网络拦截器 
          internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
          internal var retryOnConnectionFailure = true // 连接失败时重试
          internal var authenticator: Authenticator = Authenticator.NONE // 验证器
          internal var followRedirects = true // 允许重定向
          internal var followSslRedirects = true // 允许 https 同 http 之间的重定向
          internal var cookieJar: CookieJar = CookieJar.NO_COOKIES // cookie
          internal var cache: Cache? = null // 缓存
          internal var dns: Dns = Dns.SYSTEM
          internal var proxy: Proxy? = null
          internal var proxySelector: ProxySelector? = null
          internal var proxyAuthenticator: Authenticator = Authenticator.NONE
          internal var socketFactory: SocketFactory = SocketFactory.getDefault()
          internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
          internal var x509TrustManagerOrNull: X509TrustManager? = null
          internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
          internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
          internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
          internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
          internal var certificateChainCleaner: CertificateChainCleaner? = null
          internal var callTimeout = 0
          internal var connectTimeout = 10_000
          internal var readTimeout = 10_000
          internal var writeTimeout = 10_000
          internal var pingInterval = 0
          internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
          internal var routeDatabase: RouteDatabase? = null
          
          // 传入自己构建的参数
          internal constructor(okHttpClient: OkHttpClient) : this() {
            this.dispatcher = okHttpClient.dispatcher
            this.connectionPool = okHttpClient.connectionPool
            this.interceptors += okHttpClient.interceptors
            this.networkInterceptors += okHttpClient.networkInterceptors
            this.eventListenerFactory = okHttpClient.eventListenerFactory
            this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure
            this.authenticator = okHttpClient.authenticator
            this.followRedirects = okHttpClient.followRedirects
            this.followSslRedirects = okHttpClient.followSslRedirects
            this.cookieJar = okHttpClient.cookieJar
            this.cache = okHttpClient.cache
            this.dns = okHttpClient.dns
            this.proxy = okHttpClient.proxy
            this.proxySelector = okHttpClient.proxySelector
            this.proxyAuthenticator = okHttpClient.proxyAuthenticator
            this.socketFactory = okHttpClient.socketFactory
            this.sslSocketFactoryOrNull = okHttpClient.sslSocketFactoryOrNull
            this.x509TrustManagerOrNull = okHttpClient.x509TrustManager
            this.connectionSpecs = okHttpClient.connectionSpecs
            this.protocols = okHttpClient.protocols
            this.hostnameVerifier = okHttpClient.hostnameVerifier
            this.certificatePinner = okHttpClient.certificatePinner
            this.certificateChainCleaner = okHttpClient.certificateChainCleaner
            this.callTimeout = okHttpClient.callTimeoutMillis
            this.connectTimeout = okHttpClient.connectTimeoutMillis
            this.readTimeout = okHttpClient.readTimeoutMillis
            this.writeTimeout = okHttpClient.writeTimeoutMillis
            this.pingInterval = okHttpClient.pingIntervalMillis
            this.minWebSocketMessageToCompress = okHttpClient.minWebSocketMessageToCompress
            this.routeDatabase = okHttpClient.routeDatabase
          }
          
          ...
    }
    
    

    使用建造者模式,用来设置拦截器、超时时间、缓存、重定向等属性。

    2. Request

    class Request internal constructor(
      @get:JvmName("url") val url: HttpUrl,
      @get:JvmName("method") val method: String,
      @get:JvmName("headers") val headers: Headers,
      @get:JvmName("body") val body: RequestBody?,
      internal val tags: Map<Class<*>, Any>
    ) {
        
        ...
        
        
        open class Builder {
          internal var url: HttpUrl? = null
          internal var method: String
          internal var headers: Headers.Builder
          internal var body: RequestBody? = null
    
          internal var tags: MutableMap<Class<*>, Any> = mutableMapOf()
    
          constructor() {
            this.method = "GET"
            this.headers = Headers.Builder()
          }
    
          internal constructor(request: Request) {
            this.url = request.url
            this.method = request.method
            this.body = request.body
            this.tags = if (request.tags.isEmpty()) {
              mutableMapOf()
            } else {
              request.tags.toMutableMap()
            }
            this.headers = request.headers.newBuilder()
          }
    
          open fun url(url: HttpUrl): Builder = apply {
            this.url = url
          }
          
          ...
    }
    
    

    也是使用建造者模式,来设置请求方法、url、请求体、header 信息。

    3. Call

    interface Call : Cloneable {
      // 返回 call 的 request 对象
      fun request(): Request
    
      // 执行同步请求
      @Throws(IOException::class)
      fun execute(): Response
    
      // 执行异步请求
      fun enqueue(responseCallback: Callback)
        
      // 取消
      fun cancel()
      
      // 是否已经执行请求
      fun isExecuted(): Boolean
    
      // 是否已经取消
      fun isCanceled(): Boolean
      
      // 超时信息
      fun timeout(): Timeout
    
      // 克隆当前 call,返回新的对象方便再次执行请求,同一个 call 只能执行一次
      public override fun clone(): Call
    
      fun interface Factory {
        fun newCall(request: Request): Call
      }
    }
    
    

    接口类,定义了在一次请求中可能用到的方法。

    4. RealCall

    实现 Call 接口,是最终的请求执行者,下面按同步请求和异步请求分成两部分来说。

    a、同步请求部分
    // RealCall.execute
    override fun execute(): Response {
      // 每个 call 只能请求一次
      check(executed.compareAndSet(false, true)) { "Already Executed" }
    
      timeout.enter()
      callStart()
      try {
        // 将当前 call 添加到 Dispatcher 类的 runningSyncCalls 列表中
        client.dispatcher.executed(this)
        // 经过一系列拦截器拿到请求结果
        return getResponseWithInterceptorChain()
      } finally {
        // 将当前 call 从 Dispatcher 类的 runningSyncCalls 列表中移除
        client.dispatcher.finished(this)
      }
    }
    
    
    // RealCall.getResponseWithInterceptorChain
    @Throws(IOException::class)
    internal fun getResponseWithInterceptorChain(): Response {
      // Build a full stack of interceptors.
      val interceptors = mutableListOf<Interceptor>()
      // 开始添加拦截器
      // 在 OkHttpClient 中设置的 拦截器
      interceptors += client.interceptors
      // 处理重试和重定向的拦截器
      interceptors += RetryAndFollowUpInterceptor(client)
      // 将应用请求转换为网络请求,将请求结果转换为用户友好响应的拦截器
      interceptors += BridgeInterceptor(client.cookieJar)
      // 读取缓存、更新缓存的拦截器
      interceptors += CacheInterceptor(client.cache)
      // 和服务器连接的拦截器
      interceptors += ConnectInterceptor
      if (!forWebSocket) {
        // 在 OkHttpClient 中设置的 networkInterceptors 
        interceptors += client.networkInterceptors
      }
      // 请求服务器、读取响应结果的拦截器
      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() 该方法中,dispatcher 用来改变执行状态。

    b、异步请求部分
    // RealCall.enqueue
    override fun enqueue(responseCallback: Callback) {
      // 每个 call 只能请求一次
      check(executed.compareAndSet(false, true)) { "Already Executed" }
    
      callStart()
      // 将 AsyncCall 添加到 Dispatcher.readyAsyncCalls 中
      client.dispatcher.enqueue(AsyncCall(responseCallback))
    }
    
    

    接下来看 enqueue() 方法

    // Dispatcher.enqueue
    internal fun enqueue(call: AsyncCall) {
      synchronized(this) {
        // 添加到 readyAsyncCalls 中
        readyAsyncCalls.add(call)
    
        // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
        // the same host.
        if (!call.call.forWebSocket) {
          val existingCall = findExistingCallWithHost(call.host)
          if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
        }
      }
      promoteAndExecute()
    }
    
    

    接下来看 promoteAndExecute() 方法

    // Dispatcher.promoteAndExecute
    private fun promoteAndExecute(): Boolean {
      this.assertThreadDoesntHoldLock()
    
      val executableCalls = mutableListOf<AsyncCall>()
      val isRunning: Boolean
      synchronized(this) {
        val i = readyAsyncCalls.iterator()
        // 遍历 readyAsyncCalls
        while (i.hasNext()) {
          val asyncCall = i.next()
    
          if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
          if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
          // 移除自己
          i.remove()
          asyncCall.callsPerHost.incrementAndGet()
          // 添加到 executableCalls 中
          executableCalls.add(asyncCall)
          runningAsyncCalls.add(asyncCall)
        }
        isRunning = runningCallsCount() > 0
      }
      // 遍历 executableCalls 开始执行
      for (i in 0 until executableCalls.size) {
        val asyncCall = executableCalls[i]
        asyncCall.executeOn(executorService)
      }
    
      return isRunning
    }
    
    

    执行的 run 方法

    // RealCall#AsyncCall.run
    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)
        }
      }
    }
    
    

    看到这里再去看开头的流程图就很容易了

    分析了请求的大致流程,细节分析后续有待完善。

    相关文章

      网友评论

          本文标题:okhttp 请求过程源码分析

          本文链接:https://www.haomeiwen.com/subject/uypbdrtx.html