亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android開發(fā)OkHttp執(zhí)行流程源碼分析

 更新時(shí)間:2022年09月03日 10:00:41   作者:Delusion  
這篇文章主要為大家介紹了Android開發(fā)OkHttp執(zhí)行流程源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

OkHttp 是一套處理 HTTP 網(wǎng)絡(luò)請(qǐng)求的依賴庫(kù),由 Square 公司設(shè)計(jì)研發(fā)并開源,目前可以在 Java Kotlin 中使用。

對(duì)于 Android App 來(lái)說,OkHttp 現(xiàn)在幾乎已經(jīng)占據(jù)了所有的網(wǎng)絡(luò)請(qǐng)求操作讓,我們了解其內(nèi)部實(shí)現(xiàn)原理可以更好地進(jìn)行功能擴(kuò)展、封裝以及優(yōu)化。

本文基于OkHttp 4.11.0 進(jìn)行分析

OkHttp的具體使用可以參考官網(wǎng),這里不做具體的說明,本文主要從OkHttp的使用入手,來(lái)具體分析OkHttp的實(shí)現(xiàn)原理。

介紹

OkHttp是通過socket和okio進(jìn)行交換數(shù)據(jù)的

val client = OkHttpClient() 
val request = Request.Builder().get().url("http://xxx").build()
client.newCall(request).enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
    }
    override fun onResponse(call: Call, response: Response) {
    }
})

從上面我們可以看到幾個(gè)OkHttp重要的組成部分

  • OkHttpClient: Okhttp用于請(qǐng)求的執(zhí)行客戶端
  • Request: 通過Bulider設(shè)計(jì)模式,構(gòu)建的一個(gè)請(qǐng)求對(duì)象
  • Call: 是通過 client.newCall 生成的請(qǐng)求執(zhí)行對(duì)象,當(dāng)執(zhí)行了execute之后才會(huì)真正的開始執(zhí)行網(wǎng)絡(luò)請(qǐng)求
  • Response: 是通過網(wǎng)絡(luò)請(qǐng)求后,從服務(wù)器返回的信息都在里面。內(nèi)含返回的狀態(tài)碼,以及代表響應(yīng)消息正文的ResponseBody
  • interceptor 用戶定義的攔截器,在重試攔截器之前執(zhí)行
  • retryAndFollowUpInterceptor 重試攔截器
  • BridgeInterceptor 建立網(wǎng)絡(luò)橋梁的攔截器,主要是為了給網(wǎng)絡(luò)請(qǐng)求時(shí)候,添加各種各種必要參數(shù)。如Cookie,Content-type
  • CacheInterceptor 緩存攔截器,主要是為了在網(wǎng)絡(luò)請(qǐng)求時(shí)候,根據(jù)返回碼處理緩存。
  • ConnectInterceptor 連接攔截器,主要是為了從連接池子中查找可以復(fù)用的socket連接。
  • networkInterceptors 用戶定義的網(wǎng)絡(luò)攔截器,在CallServerInterceptor(執(zhí)行網(wǎng)絡(luò)請(qǐng)求攔截器)之前運(yùn)行。
  • CallServerInterceptor 真正執(zhí)行網(wǎng)絡(luò)請(qǐng)求的邏輯。

執(zhí)行流程

OkHttpClient

class Builder constructor() {
   //Okhttp 請(qǐng)求分發(fā)器,是整個(gè)OkhttpClient的執(zhí)行核心
  internal var dispatcher: Dispatcher = Dispatcher()
  //Okhttp連接池,不過會(huì)把任務(wù)委托給RealConnectionPool處理
  internal var connectionPool: ConnectionPool = ConnectionPool()
  //用戶定義的攔截器,在重試攔截器之前執(zhí)行
  internal val interceptors: MutableList<Interceptor> = mutableListOf()
  //用戶定義的網(wǎng)絡(luò)攔截器,在CallServerInterceptor(執(zhí)行網(wǎng)絡(luò)請(qǐng)求攔截器)之前運(yùn)行。
  internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
  //流程監(jiān)聽器
  internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
  //連接失敗時(shí)是否重連
  internal var retryOnConnectionFailure = true
  //服務(wù)器認(rèn)證設(shè)置
  internal var authenticator: Authenticator = Authenticator.NONE
  //是否重定向
  internal var followRedirects = true
  //是否重定向到https
  internal var followSslRedirects = true
  //cookie持久化的設(shè)置
  internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
  //緩存設(shè)置
  internal var cache: Cache? = null
  //DNS設(shè)置
  internal var dns: Dns = Dns.SYSTEM
  //代理設(shè)置
  internal var proxy: Proxy? = null
  internal var proxySelector: ProxySelector? = null
  internal var proxyAuthenticator: Authenticator = Authenticator.NONE
  //默認(rèn)的socket連接池
  internal var socketFactory: SocketFactory = SocketFactory.getDefault()
  //用于https的socket連接池
  internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
  //用于信任Https證書的對(duì)象
  internal var x509TrustManagerOrNull: X509TrustManager? = null
  internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
  //http協(xié)議集合
  internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
  //https對(duì)host的檢驗(yàn)
  internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
  internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
  internal var certificateChainCleaner: CertificateChainCleaner? = null
  //請(qǐng)求超時(shí)
  internal var callTimeout = 0
  //連接超時(shí)
  internal var connectTimeout = 10_000
  //讀取超時(shí)
  internal var readTimeout = 10_000
  //寫入超時(shí)
  internal var writeTimeout = 10_000
  internal var pingInterval = 0
  internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
  internal var routeDatabase: RouteDatabase? = null
  }

client.newCall(request):

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

在這里生成一個(gè)RealCall對(duì)象,這里第三個(gè)參數(shù)是否為websocket,默認(rèn)是false。 在拿到RealCall對(duì)象之后,這里有兩種方式起發(fā)送網(wǎng)絡(luò)請(qǐng)求:

  • execute() : 這種方式很少用
  • enqueue() : 這種方式是將每個(gè)請(qǐng)求放在隊(duì)列中,按照順序逐個(gè)去進(jìn)行消費(fèi)。

RealCall.enqueue()

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)
}

這里主要做了一下幾步

  • 首先回調(diào)eventListener的callStart()方法,
  • 然后把創(chuàng)建AsyncCall對(duì)象將responseCallback傳進(jìn)去。
  • 最后Dispatcher的enqueue()方法.

Dispatcher.enqueue()

class Dispatcher constructor() {
    ......
//按運(yùn)行順序準(zhǔn)備異步調(diào)用的隊(duì)列
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
//正在運(yùn)行的異步請(qǐng)求隊(duì)列, 包含取消但是還未finish的AsyncCall
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
//正在運(yùn)行的同步請(qǐng)求隊(duì)列, 包含取消但是還未finish的RealCall
private val runningSyncCalls = ArrayDeque<RealCall>()
    ......
internal fun enqueue(call: AsyncCall) {
  synchronized(this) {
    readyAsyncCalls.add(call)
    if (!call.call.forWebSocket) {
      val existingCall = findExistingCallWithHost(call.host)
      if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
    }
  }
  promoteAndExecute()
}
private fun findExistingCallWithHost(host: String): AsyncCall? {
  for (existingCall in runningAsyncCalls) {
    if (existingCall.host == host) return existingCall
  }
  for (existingCall in readyAsyncCalls) {
    if (existingCall.host == host) return existingCall
  }
  return null
}
  • 首先將AsyncCall加入readyAsyncCalls隊(duì)列中.
  • 然后通過findExistingCallWithHost查找在runningAsyncCalls和readyAsyncCalls是否存在相同host的AsyncCall,如果存在則調(diào)用call.reuseCallsPerHostFrom()進(jìn)行復(fù)用
  • 最后調(diào)用 promoteAndExecute() 通過線程池執(zhí)行隊(duì)列中的AsyncCall對(duì)象
private fun promoteAndExecute(): Boolean {
  this.assertThreadDoesntHoldLock()
  val executableCalls = mutableListOf<AsyncCall>()
    //判斷是否有請(qǐng)求正在執(zhí)行
  val isRunning: Boolean
   //加鎖,保證線程安全
  synchronized(this) {
   //遍歷 readyAsyncCalls 隊(duì)列
    val i = readyAsyncCalls.iterator()
    while (i.hasNext()) {
      val asyncCall = i.next()
       //runningAsyncCalls的數(shù)量不能大于最大并發(fā)請(qǐng)求數(shù) 64
      if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
      //同一Host的最大數(shù)是5
      if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
       //從readyAsyncCalls隊(duì)列中移除并加入到executableCalls和runningAsyncCalls中
      i.remove()
      asyncCall.callsPerHost.incrementAndGet()
      executableCalls.add(asyncCall)
      runningAsyncCalls.add(asyncCall)
    }
    isRunning = runningCallsCount() > 0
  }
    //遍歷executableCalls 執(zhí)行asyncCall
  for (i in 0 until executableCalls.size) {
    val asyncCall = executableCalls[i]
    asyncCall.executeOn(executorService)
  }
  return isRunning
}

在這里遍歷readyAsyncCalls隊(duì)列,判斷runningAsyncCalls的數(shù)量是否大于最大并發(fā)請(qǐng)求數(shù)64, 判斷同一Host的請(qǐng)求是否大于5,然后將AsyncCall從readyAsyncCalls隊(duì)列中移除,并加入到executableCalls和runningAsyncCalls中,遍歷executableCalls 執(zhí)行asyncCall.

internal inner class AsyncCall(
  private val responseCallback: Callback
) : Runnable {
     ......
  fun executeOn(executorService: ExecutorService) {
    client.dispatcher.assertThreadDoesntHoldLock()
    var success = false
    try {
       //執(zhí)行AsyncCall 的run方法
      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) // This call is no longer running!
      }
    }
  }
  override fun run() {
    threadName("OkHttp ${redactedUrl()}") {
      var signalledCallback = false
      timeout.enter()
      try {
         //執(zhí)行OkHttp的攔截器  獲取response對(duì)象
        val response = getResponseWithInterceptorChain()
        signalledCallback = true
        //通過該方法將response對(duì)象回調(diào)出去
        responseCallback.onResponse(this@RealCall, response)
      } catch (e: IOException) {
        if (signalledCallback) {
          Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
        } else {
            //遇到IO異常  回調(diào)失敗方法
          responseCallback.onFailure(this@RealCall, e)
        }
      } catch (t: Throwable) {
         //遇到其他異常  回調(diào)失敗方法
        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)
      }
    }
  }
}

這里可以看到AsyncCall就是一個(gè)Runable對(duì)象,線程執(zhí)行就會(huì)調(diào)用該對(duì)象的run方法,而executeOn方法就是執(zhí)行runable對(duì)象. 在run方法中主要執(zhí)行了以下幾步:

  • 調(diào)用getResponseWithInterceptorChain()執(zhí)行OkHttp攔截器,獲取response對(duì)象
  • 調(diào)用responseCallback的onResponse方法將Response對(duì)象回調(diào)出去
  • 如果遇見IOException異常則調(diào)用responseCallback的onFailure方法將異?;卣{(diào)出去
  • 如果遇到其他異常,調(diào)用cancel()方法取消請(qǐng)求,調(diào)用responseCallback的onFailure方法將異常回調(diào)出去
  • 調(diào)用Dispatcher的finished方法結(jié)束執(zhí)行
@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)
  interceptors += ConnectInterceptor
  //如果不是sockect 添加newtwork攔截器
  if (!forWebSocket) {
    interceptors += client.networkInterceptors
  }
  interceptors += CallServerInterceptor(forWebSocket)
    //構(gòu)建攔截器責(zé)任鏈
  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 {
     //執(zhí)行攔截器責(zé)任鏈獲取Response
    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)
    }
  }
}

在這里主要執(zhí)行了以下幾步操作

  • 首先構(gòu)建一個(gè)可變interceptor集合,將所有攔截器添加進(jìn)去,這里如果是websocket則不添加networkInterceptor攔截器,這個(gè)interceptor集合的添加順序也就是OkHttp攔截器的執(zhí)行順序
  • 構(gòu)建一個(gè)RealInterceptorChain對(duì)象,將所有的攔截器包裹
  • 調(diào)用RealInterceptorChain的proceed的方法,獲得Response對(duì)象

簡(jiǎn)單的總結(jié)一下:這里才用了責(zé)任鏈設(shè)計(jì)模式,構(gòu)建RealInterceptorChain對(duì)象,然后執(zhí)行proceed方法獲取response對(duì)象

fun interface Interceptor {
    //攔截方法
  @Throws(IOException::class)
  fun intercept(chain: Chain): Response
  companion object {
    inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor =
      Interceptor { block(it) }
  }
  interface Chain {
     //獲取Request對(duì)象
    fun request(): Request
    //處理請(qǐng)求獲取Reponse
    @Throws(IOException::class)
    fun proceed(request: Request): Response
    ......
  }
}
class RealInterceptorChain(
  internal val call: RealCall,
  private val interceptors: List<Interceptor>,
  private val index: Int,
  internal val exchange: Exchange?,
  internal val request: Request,
  internal val connectTimeoutMillis: Int,
  internal val readTimeoutMillis: Int,
  internal val writeTimeoutMillis: Int
) : Interceptor.Chain {
  internal fun copy(
    index: Int = this.index,
    exchange: Exchange? = this.exchange,
    request: Request = this.request,
    connectTimeoutMillis: Int = this.connectTimeoutMillis,
    readTimeoutMillis: Int = this.readTimeoutMillis,
    writeTimeoutMillis: Int = this.writeTimeoutMillis
  ) = RealInterceptorChain(call, interceptors, index, exchange, request, connectTimeoutMillis,
      readTimeoutMillis, writeTimeoutMillis)
      ......
  override fun call(): Call = call
  override fun request(): Request = request
  @Throws(IOException::class)
  override fun proceed(request: Request): Response {
    check(index < interceptors.size)
     ......
    val next = copy(index = index + 1, request = request)
    val interceptor = interceptors[index]
    @Suppress("USELESS_ELVIS")
    val response = interceptor.intercept(next) ?: throw NullPointerException(
        "interceptor $interceptor returned null")
     ......
    return response
  }
}

這里看一看到copy()方法就是創(chuàng)建了一個(gè)RealInterceptorChain()對(duì)象,不過需要注意的是index在創(chuàng)建對(duì)象時(shí)是index = index + 1,這樣就會(huì)執(zhí)行index對(duì)應(yīng)下標(biāo)的攔截器,不斷的調(diào)用下一個(gè)攔截器,直到有response對(duì)象返回,也就是chain.proceed(originalRequest)結(jié)束。

Interceptor

下面我們來(lái)具體分析一下攔截器

RetryAndFollowUpInterceptor

主要處理了如下幾個(gè)方向的問題:

  • 1.異常,或者協(xié)議重試(408客戶端超時(shí),權(quán)限問題,503服務(wù)暫時(shí)不處理,retry-after為0)
  • 2.重定向
  • 3.重試的次數(shù)不能超過20次。
@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) {
  //這里會(huì)新建一個(gè)ExchangeFinder,ConnectInterceptor會(huì)使用到
  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) {
      //嘗試通過路由連接失敗。該請(qǐng)求將不會(huì)被發(fā)送。
      if (!recover(e.lastConnectException, call, request, requestSendStarted = false)) {
        throw e.firstConnectException.withSuppressed(recoveredFailures)
      } else {
        recoveredFailures += e.firstConnectException
      }
      newExchangeFinder = false
      continue
    } catch (e: IOException) {
      //嘗試與服務(wù)器通信失敗。該請(qǐng)求可能已發(fā)送。
      if (!recover(e, call, request, requestSendStarted = e !is ConnectionShutdownException)) {
        throw e.withSuppressed(recoveredFailures)
      } else {
        recoveredFailures += e
      }
      newExchangeFinder = false
      continue
    }
   //嘗試關(guān)聯(lián)上一個(gè)response,注意:body是為null
    if (priorResponse != null) {
      response = response.newBuilder()
          .priorResponse(priorResponse.newBuilder()
              .body(null)
              .build())
          .build()
    }
    val exchange = call.interceptorScopedExchange
    //會(huì)根據(jù) responseCode 來(lái)判斷,構(gòu)建一個(gè)新的request并返回來(lái)重試或者重定向
    val followUp = followUpRequest(response, exchange)
    if (followUp == null) {
      if (exchange != null && exchange.isDuplex) {
        call.timeoutEarlyExit()
      }
      closeActiveExchange = false
      return response
    }
    //如果請(qǐng)求體是一次性的,不需要再次重試
    val followUpBody = followUp.body
    if (followUpBody != null && followUpBody.isOneShot()) {
      closeActiveExchange = false
      return response
    }
    response.body?.closeQuietly()
    //最大重試次數(shù),不同的瀏覽器是不同的,比如:Chrome為21,Safari則是16
    if (++followUpCount > MAX_FOLLOW_UPS) {
        throw ProtocolException("Too many follow-up requests: $followUpCount")
    }
    request = followUp
    priorResponse = response
  } finally {
    call.exitNetworkInterceptorExchange(closeActiveExchange)
  }
}
}
  • 1.調(diào)用RealCall的enterNetworkInterceptorExchange方法實(shí)例化一個(gè)ExchangeFinder在RealCall對(duì)象中。
  • 2.執(zhí)行RealCall的proceed 方法,進(jìn)入下一個(gè)攔截器,進(jìn)行下一步的請(qǐng)求處理。
  • 3.如果出現(xiàn)路由異常,則通過recover方法校驗(yàn),當(dāng)前的連接是否可以重試,不能重試則拋出異常,離開當(dāng)前的循環(huán)。
private fun recover(
  e: IOException,
  call: RealCall,
  userRequest: Request,
  requestSendStarted: Boolean
): Boolean {
  //禁止重連
  if (!client.retryOnConnectionFailure) return false
  // 不能再次發(fā)送請(qǐng)求體
  if (requestSendStarted && requestIsOneShot(e, userRequest)) return false
  // 致命異常
  if (!isRecoverable(e, requestSendStarted)) return false
  // 沒有更多線路可以重連
  if (!call.retryAfterFailure()) return false
  // 對(duì)于故障恢復(fù),將相同的路由選擇器與新連接一起使用
  return true
}

BridgeInterceptor

主要處理了如下幾個(gè)問題:

  • 主要將Content-Type、Content-Length、Host等一些數(shù)據(jù)添加到頭部。
  • 拿到數(shù)據(jù)之后對(duì)數(shù)據(jù)進(jìn)行處理,判斷是否為gzip,進(jìn)行對(duì)數(shù)據(jù)數(shù)據(jù)解壓。
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
  //獲取原始請(qǐng)求數(shù)據(jù)
  val userRequest = chain.request()
  val requestBuilder = userRequest.newBuilder()
   //重新構(gòu)建請(qǐng)求 添加一些必要的請(qǐng)求頭信息
  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")
  }
  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)
  }
    //執(zhí)行下一個(gè)攔截器
  val networkResponse = chain.proceed(requestBuilder.build())
  cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)
  //創(chuàng)建一個(gè)新的responseBuilder,目的是將原始請(qǐng)求數(shù)據(jù)構(gòu)建到response中
  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()
       //修改response header信息,移除Content-Encoding,Content-Length信息
      responseBuilder.headers(strippedHeaders)
      val contentType = networkResponse.header("Content-Type"
     //修改response body信息
      responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))
    }
  }
  return responseBuilder.build()
}
  • 設(shè)置頭部的Content-Type.說明內(nèi)容類型是什么
  • 如果contentLength大于等于0,則設(shè)置頭部的Content-Length(說明內(nèi)容大小是多少);否則設(shè)置頭部的Transfer-Encoding為chunked(說明傳輸編碼為分塊傳輸)
  • 如果Host不存在,設(shè)置頭部的Host(在Http 1.1之后出現(xiàn),可以通過同一個(gè)URL訪問到不同主機(jī),從而實(shí)現(xiàn)服務(wù)器虛擬服務(wù)器的負(fù)載均衡。如果1.1之后不設(shè)置就會(huì)返回404)。
  • 如果Connection不存在,設(shè)置頭部的Connection為Keep-Alive(代表連接狀態(tài)需要保持活躍)
  • 如果Accept-Encoding且Range為空,則強(qiáng)制設(shè)置Accept-Encoding為gzip(說明請(qǐng)求將會(huì)以gzip方式壓縮)
  • 從CookieJar的緩存中取出cookie設(shè)置到頭部的Cookie
  • 如果User-Agent為空,則設(shè)置User-Agent到頭部

CacheInterceptor

用戶通過OkHttpClient.cache來(lái)配置緩存,緩存攔截器通過CacheStrategy來(lái)判斷是使用網(wǎng)絡(luò)還是緩存來(lái)構(gòu)建response。

@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
  val call = chain.call()
  //通過request從OkHttpClient.cache中獲取緩存
  val cacheCandidate = cache?.get(chain.request())
  val now = System.currentTimeMillis()
 //創(chuàng)建緩存策略
  val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()
    //為空表示不使用網(wǎng)絡(luò),反之,則表示使用網(wǎng)絡(luò)
    val networkRequest = strategy.networkRequest
    //為空表示不使用緩存,反之,則表示使用緩存
    val cacheResponse = strategy.cacheResponse
    //追蹤網(wǎng)絡(luò)與緩存的使用情況
    cache?.trackResponse(strategy)
    val listener = (call as? RealCall)?.eventListener ?: EventListener.NONE
    //有緩存但不適用,關(guān)閉它
    if (cacheCandidate != null && cacheResponse == null) {
      cacheCandidate.body?.closeQuietly()
    }
    //如果網(wǎng)絡(luò)被禁止,但是緩存又是空的,構(gòu)建一個(gè)code為504的response,并返回
  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)
        }
  }
 //如果我們禁用了網(wǎng)絡(luò)不使用網(wǎng)絡(luò),且有緩存,直接根據(jù)緩存內(nèi)容構(gòu)建并返回response
  if (networkRequest == null) {
    return cacheResponse!!.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .build().also {
          listener.cacheHit(call, it)
        }
  }
   //為緩存添加監(jiān)聽
  if (cacheResponse != null) {
    listener.cacheConditionalHit(call, cacheResponse)
  } else if (cache != null) {
    listener.cacheMiss(call)
  }
  var networkResponse: Response? = null
  try {
      //執(zhí)行下一個(gè)攔截器
    networkResponse = chain.proceed(networkRequest)
  } finally {
    //捕獲I/O或其他異常,請(qǐng)求失敗,networkResponse為空,且有緩存的時(shí)候,不暴露緩存內(nèi)容
    if (networkResponse == null && cacheCandidate != null) {
       //否則關(guān)閉緩存響應(yīng)體
      cacheCandidate.body?.closeQuietly()
    }
  }
    //如果有緩存
  if (cacheResponse != null) {
    //且網(wǎng)絡(luò)返回response code為304的時(shí)候,使用緩存內(nèi)容新構(gòu)建一個(gè)Response返回。
    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()
      cache!!.trackConditionalCacheHit()
      cache.update(cacheResponse, response)
      return response.also {
        listener.cacheHit(call, it)
      }
    } else {
    //否則關(guān)閉緩存響應(yīng)體
      cacheResponse.body?.closeQuietly()
    }
  }
  //構(gòu)建網(wǎng)絡(luò)請(qǐng)求的response
  val response = networkResponse!!.newBuilder()
      .cacheResponse(stripBody(cacheResponse))
      .networkResponse(stripBody(networkResponse))
      .build()
    //如果cache不為null,即用戶在OkHttpClient中配置了緩存,則將上一步新構(gòu)建的網(wǎng)絡(luò)請(qǐng)求response存到cache中
  if (cache != null) {
    //根據(jù)response的code,header以及CacheControl.noStore來(lái)判斷是否可以緩存
    if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {
     // 將該response存入緩存
      val cacheRequest = cache.put(response)
      return cacheWritingResponse(cacheRequest, response).also {
        if (cacheResponse != null) {
          listener.cacheMiss(call)
        }
      }
    }
    //根據(jù)請(qǐng)求方法來(lái)判斷緩存是否有效,只對(duì)Get請(qǐng)求進(jìn)行緩存,其它方法的請(qǐng)求則移除
    if (HttpMethod.invalidatesCache(networkRequest.method)) {
      try {
         //緩存無(wú)效,將該請(qǐng)求緩存從client緩存配置中移除
        cache.remove(networkRequest)
      } catch (_: IOException) {
      }
    }
  }
  return response
}

網(wǎng)絡(luò)請(qǐng)求前:

  • 首先根據(jù)request從OkHttpClient.cache中獲取緩存,通過CacheStrategy獲取本次請(qǐng)求的請(qǐng)求體及緩存的響應(yīng)體。
  • 如果 請(qǐng)求體networkRequest和響應(yīng)體cacheResponse都為空的話,則返回錯(cuò)誤碼為 504
  • 如果 請(qǐng)求體networkRequest為空 響應(yīng)體cacheResponse不為空的話,則將該響應(yīng)體返回
  • 如果請(qǐng)求體networkRequest不為空的話,則進(jìn)入下一個(gè)攔截器。

網(wǎng)絡(luò)請(qǐng)求后:

  • 如果當(dāng)前cacheResponse不為空,且 networkResponse狀態(tài)碼為304, 則代表數(shù)據(jù)沒有變化,那么就會(huì)根據(jù) cacheResponse 構(gòu)建一個(gè)新的 response,根據(jù)當(dāng)前時(shí)間更新到緩存當(dāng)中,并返回到上一攔截器中
  • 如果networkResponse狀態(tài)碼不為304,則判斷是否進(jìn)行緩存,最后返回到上一攔截器中

從LruCache中獲取緩存

val cacheCandidate = cache?.get(chain.request())
internal fun get(request: Request): Response? {
  val key = key(request.url)
  val snapshot: DiskLruCache.Snapshot = try {
    cache[key] ?: return null
  } catch (_: IOException) {
    return null // Give up because the cache cannot be read.
  }
  val entry: Entry = try {
    Entry(snapshot.getSource(ENTRY_METADATA))
  } catch (_: IOException) {
    snapshot.closeQuietly()
    return null
  }
  val response = entry.response(snapshot)
  if (!entry.matches(request, response)) {
    response.body?.closeQuietly()
    return null
  }
  return response
}
@JvmStatic
fun key(url: HttpUrl): String = url.toString().encodeUtf8().md5().hex()
  • 首先將url轉(zhuǎn)化為urf-8,并且通過md5拿到摘要,再調(diào)用hex獲取16進(jìn)制的字符串,該字符串就是LruCache的key;
  • 通過key獲取到DiskLruCache.Snapshot對(duì)象(這里在DiskLruCache中重寫了get方法),根據(jù)DiskLruCache.Snapshot對(duì)象獲取到okio 的source。

DiskLruCache:

@Synchronized @Throws(IOException::class)
operator fun get(key: String): Snapshot? {
  initialize()
  checkNotClosed()
  validateKey(key)
  val entry = lruEntries[key] ?: return null
  val snapshot = entry.snapshot() ?: return null
  redundantOpCount++
  journalWriter!!.writeUtf8(READ)
      .writeByte(' '.toInt())
      .writeUtf8(key)
      .writeByte('\n'.toInt())
  if (journalRebuildRequired()) {
    cleanupQueue.schedule(cleanupTask)
  }
  return snapshot
}
  • 最后將數(shù)據(jù)轉(zhuǎn)化為響應(yīng)體

再來(lái)看看那些響應(yīng)體需要緩存:

這里是網(wǎng)絡(luò)請(qǐng)求回來(lái),判斷是否需要緩存的處理

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) {
    }
  }
}
  • 首先根據(jù)cache對(duì)象是否為空,決定是否進(jìn)入緩存判斷
  • response.promisesBody()判斷響應(yīng)體是否有正文,CacheStrategy.isCacheable(response, networkRequest)這里是判斷哪些狀態(tài)碼需要緩存
  • 這里HttpMethod.invalidatesCache(networkRequest.method)判斷哪些請(qǐng)求方式是否為POST、PATCH、PUT、DELETEMOVE,如果為true的話則移除緩存。
fun isCacheable(response: Response, request: Request): Boolean {
  when (response.code) {
    HTTP_OK,
    HTTP_NOT_AUTHORITATIVE,
    HTTP_NO_CONTENT,
    HTTP_MULT_CHOICE,
    HTTP_MOVED_PERM,
    HTTP_NOT_FOUND,
    HTTP_BAD_METHOD,
    HTTP_GONE,
    HTTP_REQ_TOO_LONG,
    HTTP_NOT_IMPLEMENTED,
    StatusLine.HTTP_PERM_REDIRECT -> {
    }
    HTTP_MOVED_TEMP,
    StatusLine.HTTP_TEMP_REDIRECT -> {
      if (response.header("Expires") == null &&
          response.cacheControl.maxAgeSeconds == -1 &&
          !response.cacheControl.isPublic &&
          !response.cacheControl.isPrivate) {
        return false
      }
    }
    else -> {
      return false
    }
  }
  return !response.cacheControl.noStore && !request.cacheControl.noStore
}

如果狀態(tài)碼為200203、204、301404、405、410414、501、308 都可以緩存,其他則返回false 不進(jìn)行緩存

以上就是Android開發(fā)OkHttp執(zhí)行流程源碼分析的詳細(xì)內(nèi)容,更多關(guān)于Android OkHttp執(zhí)行流程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解Android短信的發(fā)送和廣播接收實(shí)現(xiàn)短信的監(jiān)聽

    詳解Android短信的發(fā)送和廣播接收實(shí)現(xiàn)短信的監(jiān)聽

    本篇文章主要介紹了Android短信的發(fā)送和廣播接收實(shí)現(xiàn)短信的監(jiān)聽,可以實(shí)現(xiàn)短信收發(fā),有興趣的可以了解一下。
    2016-11-11
  • Android 中SwipeRefreshLayout與ViewPager滑動(dòng)事件沖突解決方法

    Android 中SwipeRefreshLayout與ViewPager滑動(dòng)事件沖突解決方法

    這篇文章主要介紹了Android 中SwipeRefreshLayout與ViewPager滑動(dòng)事件沖突解決方法的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Android切圓角的幾種常見方式總結(jié)

    Android切圓角的幾種常見方式總結(jié)

    這篇文章主要給大家介紹了關(guān)于Android切圓角的常見方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Android notifyDataSetChanged() 動(dòng)態(tài)更新ListView案例詳解

    Android notifyDataSetChanged() 動(dòng)態(tài)更新ListView案例詳解

    這篇文章主要介紹了Android notifyDataSetChanged() 動(dòng)態(tài)更新ListView案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Kotlin Jetpack組件ViewModel使用詳解

    Kotlin Jetpack組件ViewModel使用詳解

    作為Jetpack組件之一的ViewModel,也是框架MVVM中的一部分,其功能主要用于屏幕反轉(zhuǎn)后的數(shù)據(jù)保存;因?yàn)锳ctivity翻轉(zhuǎn)屏幕后或?qū)崿F(xiàn)onCreat()方法,也就是說會(huì)重新創(chuàng)建頁(yè)面,之前頁(yè)面的臨時(shí)數(shù)據(jù)都會(huì)清除
    2022-12-12
  • 詳談Android動(dòng)畫效果translate、scale、alpha、rotate

    詳談Android動(dòng)畫效果translate、scale、alpha、rotate

    下面小編就為大家?guī)?lái)一篇詳談Android動(dòng)畫效果translate、scale、alpha、rotate。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2017-01-01
  • android listview進(jìn)階實(shí)例分享

    android listview進(jìn)階實(shí)例分享

    這篇文章主要介紹了android listview進(jìn)階實(shí)例分享,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • Android遠(yuǎn)程獲取圖片并本地緩存

    Android遠(yuǎn)程獲取圖片并本地緩存

    這篇文章主要介紹了Android遠(yuǎn)程獲取圖片并本地緩存方法,對(duì)于遠(yuǎn)程圖片等相對(duì)比較大的資源采用異步線程中去獲取本地做緩存,感興趣的小伙伴們可以參考一下
    2016-02-02
  • Glide用法與技巧以及優(yōu)秀庫(kù)的推薦

    Glide用法與技巧以及優(yōu)秀庫(kù)的推薦

    今天小編就為大家分享一篇關(guān)于Glide用法與技巧以及優(yōu)秀庫(kù)的推薦,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • Android生成隨機(jī)數(shù)的方法實(shí)例

    Android生成隨機(jī)數(shù)的方法實(shí)例

    這篇文章主要為大家詳細(xì)介紹了Android生成隨機(jī)數(shù)的方法實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03

最新評(píng)論