前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OkHttp源码流程分析

OkHttp源码流程分析

原创
作者头像
花落花相惜
修改2021-11-24 14:24:02
4660
修改2021-11-24 14:24:02
举报
文章被收录于专栏:花落的技术专栏

请求方式

代码语言:txt
复制
fun load() {
代码语言:txt
复制
      //1.创建请求(包含url,method,headers,body)
代码语言:txt
复制
      val request = Request
代码语言:txt
复制
              .Builder()
代码语言:txt
复制
              .url("")
代码语言:txt
复制
              .build()
代码语言:txt
复制
       //2.创建OkHttpClient (包含分发器、拦截器、DNS等)
代码语言:txt
复制
       val okHttpClient = OkHttpClient.Builder().build()
代码语言:txt
复制
       //3.创建Call(用于调用请求)
代码语言:txt
复制
       val newCall = okHttpClient.newCall(request)
代码语言:txt
复制
       //4.通过异步请求数据
代码语言:txt
复制
       newCall.enqueue(object :Callback{
代码语言:txt
复制
           override fun onFailure(call: Call, e: IOException) {}
代码语言:txt
复制
           override fun onResponse(call: Call, response: Response) {}
代码语言:txt
复制
       })
代码语言:txt
复制
       //4.通过同步请求数据
代码语言:txt
复制
       val response =  newCall.execute()
代码语言:txt
复制
}

我们会按照顺序来分析一下请求的流程

前面1,2,3步很多文章已经分析过很多遍了 也比较简单 同学们可以自己看一下 我们就不再赘述 我们直接看第四步进入今天的主要流程

Okhttp请求分为同步方式和异步方式 不过最终都是殊途同归 我们以异步的方式分析一下请求流程

enqueue()

话不多说 先看一眼代码

代码语言:txt
复制
RealCall.enqueue()->
代码语言:txt
复制
Dispatcher.enqueue()->
代码语言:txt
复制
Dispatcher.promoteAndExecute()->
代码语言:txt
复制
RealCall.executeOn()
代码语言:txt
复制
override fun enqueue(responseCallback: Callback) {
代码语言:txt
复制
    synchronized(this) {
代码语言:txt
复制
        //检查是否已经开始运行
代码语言:txt
复制
      check(!executed) { "Already Executed" }
代码语言:txt
复制
      executed = true
代码语言:txt
复制
    }
代码语言:txt
复制
    callStart()
代码语言:txt
复制
    //封装AsyncCall对象 并放入队列中等待执行
代码语言:txt
复制
    client.dispatcher.enqueue(AsyncCall(responseCallback))
代码语言:txt
复制
  }
代码语言:txt
复制
internal fun enqueue(call: AsyncCall) {
代码语言:txt
复制
    synchronized(this) {
代码语言:txt
复制
        //放入等待队列
代码语言:txt
复制
      readyAsyncCalls.add(call)
代码语言:txt
复制
      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
代码语言:txt
复制
      // the same host.
代码语言:txt
复制
      if (!call.call.forWebSocket) {
代码语言:txt
复制
        val existingCall = findExistingCallWithHost(call.host)
代码语言:txt
复制
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    //推进执行
代码语言:txt
复制
    promoteAndExecute()
代码语言:txt
复制
  }
代码语言:txt
复制
//将readyAsyncCalls中合格的请求过渡升级到runningAsyncCalls中
代码语言:txt
复制
private fun promoteAndExecute(): Boolean {
代码语言:txt
复制
    this.assertThreadDoesntHoldLock()
代码语言:txt
复制
    val executableCalls = mutableListOf<AsyncCall>()
代码语言:txt
复制
    val isRunning: Boolean
代码语言:txt
复制
    synchronized(this) {
代码语言:txt
复制
      val i = readyAsyncCalls.iterator()
代码语言:txt
复制
      while (i.hasNext()) {
代码语言:txt
复制
        val asyncCall = i.next()
代码语言:txt
复制
        if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.//运行最大64
代码语言:txt
复制
        if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.每个主机最大5
代码语言:txt
复制
        i.remove()
代码语言:txt
复制
        asyncCall.callsPerHost.incrementAndGet()
代码语言:txt
复制
        executableCalls.add(asyncCall)
代码语言:txt
复制
        runningAsyncCalls.add(asyncCall)
代码语言:txt
复制
      }
代码语言:txt
复制
      isRunning = runningCallsCount() > 0
代码语言:txt
复制
    }
代码语言:txt
复制
    for (i in 0 until executableCalls.size) {
代码语言:txt
复制
      val asyncCall = executableCalls[i]
代码语言:txt
复制
      asyncCall.executeOn(executorService)
代码语言:txt
复制
    }
代码语言:txt
复制
    return isRunning
代码语言:txt
复制
  }

上面的流程主要是将我们的异步任务放入队列中 并且将可以运行的任务开启运行

RealCall.executeOn()

代码语言:txt
复制
fun executeOn(executorService: ExecutorService) {
代码语言:txt
复制
      client.dispatcher.assertThreadDoesntHoldLock()
代码语言:txt
复制
      var success = false
代码语言:txt
复制
      try {
代码语言:txt
复制
            //将当前Runnable放到线程池中运行
代码语言:txt
复制
        executorService.execute(this)
代码语言:txt
复制
        success = true
代码语言:txt
复制
      } catch (e: RejectedExecutionException) {
代码语言:txt
复制
        val ioException = InterruptedIOException("executor rejected")
代码语言:txt
复制
        ioException.initCause(e)
代码语言:txt
复制
        noMoreExchanges(ioException)
代码语言:txt
复制
        responseCallback.onFailure(this@RealCall, ioException)
代码语言:txt
复制
      } finally {
代码语言:txt
复制
        if (!success) {
代码语言:txt
复制
          client.dispatcher.finished(this) // This call is no longer running!
代码语言:txt
复制
        }
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
override fun run() {
代码语言:txt
复制
      threadName("OkHttp ${redactedUrl()}") {
代码语言:txt
复制
        var signalledCallback = false
代码语言:txt
复制
        timeout.enter()
代码语言:txt
复制
        try {
代码语言:txt
复制
        //终于到这篇文章的重头戏了
代码语言:txt
复制
          val response = getResponseWithInterceptorChain()
代码语言:txt
复制
          signalledCallback = true
代码语言:txt
复制
          responseCallback.onResponse(this@RealCall, response)
代码语言:txt
复制
        } catch (e: IOException) {
代码语言:txt
复制
          if (signalledCallback) {
代码语言:txt
复制
            // Do not signal the callback twice!
代码语言:txt
复制
            Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
代码语言:txt
复制
          } else {
代码语言:txt
复制
            responseCallback.onFailure(this@RealCall, e)
代码语言:txt
复制
          }
代码语言:txt
复制
        } catch (t: Throwable) {
代码语言:txt
复制
          cancel()
代码语言:txt
复制
          if (!signalledCallback) {
代码语言:txt
复制
            val canceledException = IOException("canceled due to $t")
代码语言:txt
复制
            canceledException.addSuppressed(t)
代码语言:txt
复制
            responseCallback.onFailure(this@RealCall, canceledException)
代码语言:txt
复制
          }
代码语言:txt
复制
          throw t
代码语言:txt
复制
        } finally {
代码语言:txt
复制
          client.dispatcher.finished(this)
代码语言:txt
复制
        }
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
  }

我们知道OkHttp采用了拦截链模式 看一下何为拦截器模式

借用一下大佬的图(懒得画图了😁)

3631399-0626631d246373a4.png

我们可以看到 请求链会以链的形式调用下去 直到到链尾或者return response

getResponseWithInterceptorChain()

代码语言:txt
复制
 @Throws(IOException::class)
代码语言:txt
复制
  internal fun getResponseWithInterceptorChain(): Response {
代码语言:txt
复制
    // Build a full stack of interceptors.
代码语言:txt
复制
    val interceptors = mutableListOf<Interceptor>()
代码语言:txt
复制
    //加入我们自己的拦截器
代码语言:txt
复制
    interceptors += client.interceptors
代码语言:txt
复制
    interceptors += RetryAndFollowUpInterceptor(client)
代码语言:txt
复制
    interceptors += BridgeInterceptor(client.cookieJar)
代码语言:txt
复制
    interceptors += CacheInterceptor(client.cache)
代码语言:txt
复制
    interceptors += ConnectInterceptor
代码语言:txt
复制
    if (!forWebSocket) {
代码语言:txt
复制
        //如果不是websocket的话 加入网络拦截器
代码语言:txt
复制
      interceptors += client.networkInterceptors
代码语言:txt
复制
    }
代码语言:txt
复制
    interceptors += CallServerInterceptor(forWebSocket)
代码语言:txt
复制
    val chain = RealInterceptorChain(
代码语言:txt
复制
        call = this,
代码语言:txt
复制
        interceptors = interceptors,
代码语言:txt
复制
        index = 0,
代码语言:txt
复制
        exchange = null,
代码语言:txt
复制
        request = originalRequest,
代码语言:txt
复制
        connectTimeoutMillis = client.connectTimeoutMillis,
代码语言:txt
复制
        readTimeoutMillis = client.readTimeoutMillis,
代码语言:txt
复制
        writeTimeoutMillis = client.writeTimeoutMillis
代码语言:txt
复制
    )
代码语言:txt
复制
    var calledNoMoreExchanges = false
代码语言:txt
复制
    try {
代码语言:txt
复制
        //开始拦截链调用
代码语言:txt
复制
      val response = chain.proceed(originalRequest)
代码语言:txt
复制
      if (isCanceled()) {
代码语言:txt
复制
        response.closeQuietly()
代码语言:txt
复制
        throw IOException("Canceled")
代码语言:txt
复制
      }
代码语言:txt
复制
      return response
代码语言:txt
复制
    } catch (e: IOException) {
代码语言:txt
复制
      calledNoMoreExchanges = true
代码语言:txt
复制
      throw noMoreExchanges(e) as Throwable
代码语言:txt
复制
    } finally {
代码语言:txt
复制
      if (!calledNoMoreExchanges) {
代码语言:txt
复制
        noMoreExchanges(null)
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
  }
代码语言:txt
复制
@Throws(IOException::class)
代码语言:txt
复制
  override fun proceed(request: Request): Response {
代码语言:txt
复制
    check(index < interceptors.size)
代码语言:txt
复制
    calls++
代码语言:txt
复制
    if (exchange != null) {
代码语言:txt
复制
      check(exchange.finder.sameHostAndPort(request.url)) {
代码语言:txt
复制
        "network interceptor ${interceptors[index - 1]} must retain the same host and port"
代码语言:txt
复制
      }
代码语言:txt
复制
      check(calls == 1) {
代码语言:txt
复制
        "network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    // Call the next interceptor in the chain.
代码语言:txt
复制
    //循环拿取下一个拦截器
代码语言:txt
复制
    val next = copy(index = index + 1, request = request)
代码语言:txt
复制
    val interceptor = interceptors[index]
代码语言:txt
复制
    @Suppress("USELESS_ELVIS")
代码语言:txt
复制
    //这里会调用拦截器的方法  接下来我们会分析各个拦截器的作用
代码语言:txt
复制
    val response = interceptor.intercept(next) ?: throw NullPointerException(
代码语言:txt
复制
        "interceptor $interceptor returned null")
代码语言:txt
复制
    if (exchange != null) {
代码语言:txt
复制
      check(index + 1 >= interceptors.size || next.calls == 1) {
代码语言:txt
复制
        "network interceptor $interceptor must call proceed() exactly once"
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    check(response.body != null) { "interceptor $interceptor returned a response with no body" }
代码语言:txt
复制
    return response
代码语言:txt
复制
  }

我们看到拦截器的链路模式 其实就是遍历调用各拦截器 对Request进行作用 直到return response

我们来逐个分析一下各个拦截器的作用 本文只分析处理Request,response的处理会在下文讲解

RetryAndFollowUpInterceptor

作用:处理错误 重定向 所以在请求的过程中 没有做太多事情 下文会分析如何处理错误 重定向

这个拦截器在请求的过程中几乎没做什么事情 只做了一件事 就是创建ExchangeFinder

这个对象在后面的ConnectInterceptor用来生成exchange对象

代码语言:txt
复制
fun enterNetworkInterceptorExchange(request: Request, newExchangeFinder: Boolean) {
代码语言:txt
复制
    check(interceptorScopedExchange == null)
代码语言:txt
复制
    check(exchange == null) {
代码语言:txt
复制
      "cannot make a new request because the previous response is still open: " +
代码语言:txt
复制
          "please call response.close()"
代码语言:txt
复制
    }
代码语言:txt
复制
    if (newExchangeFinder) {
代码语言:txt
复制
      this.exchangeFinder = ExchangeFinder(
代码语言:txt
复制
          connectionPool,
代码语言:txt
复制
          createAddress(request.url),
代码语言:txt
复制
          this,
代码语言:txt
复制
          eventListener
代码语言:txt
复制
      )
代码语言:txt
复制
    }
代码语言:txt
复制
  }

BridgeInterceptor

作用:添加必要的请求头信息、gzip处理等

代码语言:txt
复制
@Throws(IOException::class)
代码语言:txt
复制
  override fun intercept(chain: Interceptor.Chain): Response {
代码语言:txt
复制
    val userRequest = chain.request()
代码语言:txt
复制
    val requestBuilder = userRequest.newBuilder()
代码语言:txt
复制
    val body = userRequest.body
代码语言:txt
复制
    if (body != null) {
代码语言:txt
复制
      val contentType = body.contentType()
代码语言:txt
复制
      if (contentType != null) {
代码语言:txt
复制
            //添加contentType
代码语言:txt
复制
        requestBuilder.header("Content-Type", contentType.toString())
代码语言:txt
复制
      }
代码语言:txt
复制
      val contentLength = body.contentLength()
代码语言:txt
复制
      if (contentLength != -1L) {
代码语言:txt
复制
        requestBuilder.header("Content-Length", contentLength.toString())
代码语言:txt
复制
        requestBuilder.removeHeader("Transfer-Encoding")
代码语言:txt
复制
      } else {
代码语言:txt
复制
        requestBuilder.header("Transfer-Encoding", "chunked")
代码语言:txt
复制
        requestBuilder.removeHeader("Content-Length")
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    if (userRequest.header("Host") == null) {
代码语言:txt
复制
      requestBuilder.header("Host", userRequest.url.toHostHeader())
代码语言:txt
复制
    }
代码语言:txt
复制
    //默认keep-Alive
代码语言:txt
复制
    if (userRequest.header("Connection") == null) {
代码语言:txt
复制
      requestBuilder.header("Connection", "Keep-Alive")
代码语言:txt
复制
    }
代码语言:txt
复制
    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
代码语言:txt
复制
    // the transfer stream.
代码语言:txt
复制
    //传输流的压缩方式 默认gzip方式
代码语言:txt
复制
    var transparentGzip = false
代码语言:txt
复制
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
代码语言:txt
复制
      transparentGzip = true
代码语言:txt
复制
      requestBuilder.header("Accept-Encoding", "gzip")
代码语言:txt
复制
    }
代码语言:txt
复制
    val cookies = cookieJar.loadForRequest(userRequest.url)
代码语言:txt
复制
    //添加cookie
代码语言:txt
复制
    if (cookies.isNotEmpty()) {
代码语言:txt
复制
      requestBuilder.header("Cookie", cookieHeader(cookies))
代码语言:txt
复制
    }
代码语言:txt
复制
    //默认UA
代码语言:txt
复制
    if (userRequest.header("User-Agent") == null) {
代码语言:txt
复制
      requestBuilder.header("User-Agent", userAgent)
代码语言:txt
复制
    }
代码语言:txt
复制
    val networkResponse = chain.proceed(requestBuilder.build())
代码语言:txt
复制
    ......handle response
代码语言:txt
复制
  }

CacheInterceptor

okhttp默认的缓存机制会加快响应流程 我们看一下缓存策略 首先 我们要解释几个变量

代码语言:txt
复制
//缓存策略类
代码语言:txt
复制
class CacheStrategy{
代码语言:txt
复制
    //如果我们需要请求网络 则networkRequest不为null 否则为null
代码语言:txt
复制
    val networkRequest: Request?
代码语言:txt
复制
    //请求的返回或者请求的响应 如果无法使用缓存(一般是过期或者无缓存 则为null)
代码语言:txt
复制
    val cacheResponse: Response?
代码语言:txt
复制
}

上面两个变量是缓存策略中比较重要的两个变量 我们会根据这两个变量来选择是否命中缓存

先看一下结论

networkRequest\cacheResponse | cacheResponse is null | cacheResponse is not

null

---|---|---

networkRequest is null | ① 返回HTTP_GATEWAY_TIMEOUT 504错误 | ② 直接使用缓存

networkRequest is not null | ③ 进行网络请求 并且缓存新response | ④ 先请求 根据code(304)

判断是否需要重新request

再看一下intercept()方法 可以对照上面两个变量的解释和表格来观看

代码语言:txt
复制
override fun intercept(chain: Interceptor.Chain): Response {
代码语言:txt
复制
    //获取缓存 如果我们配置了缓存 那么会去查找是否存在cache 
代码语言:txt
复制
    //这里需要注意的一点是 okhttp默认并不会配置缓存 只是规范了一套缓存策略 我们可以自己通过OkHttpClient.Builder 的 cache 方法设置
代码语言:txt
复制
    val cacheCandidate = cache?.get(chain.request())
代码语言:txt
复制
    val now = System.currentTimeMillis()
代码语言:txt
复制
    //这里的策略 会自动判断是否使用缓存 是否存在缓存
代码语言:txt
复制
    val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()
代码语言:txt
复制
    //这里就是上面我们解释过的两个变量
代码语言:txt
复制
    val networkRequest = strategy.networkRequest
代码语言:txt
复制
    val cacheResponse = strategy.cacheResponse
代码语言:txt
复制
    cache?.trackResponse(strategy)
代码语言:txt
复制
    //LruCache没有hit cache 并且网络缓存不可用 
代码语言:txt
复制
    if (cacheCandidate != null && cacheResponse == null) {
代码语言:txt
复制
      // The cache candidate wasn't applicable. Close it.
代码语言:txt
复制
      //关闭cacheCandidate.body
代码语言:txt
复制
      cacheCandidate.body?.closeQuietly()
代码语言:txt
复制
    }
代码语言:txt
复制
    //按照我们上面对缓存的解释 不允许使用网络请求 并且当前没有缓存 对应表格中①
代码语言:txt
复制
    // If we're forbidden from using the network and the cache is insufficient, fail.
代码语言:txt
复制
    if (networkRequest == null && cacheResponse == null) {
代码语言:txt
复制
      return Response.Builder()
代码语言:txt
复制
          .request(chain.request())
代码语言:txt
复制
          .protocol(Protocol.HTTP_1_1)
代码语言:txt
复制
          .code(HTTP_GATEWAY_TIMEOUT)
代码语言:txt
复制
          .message("Unsatisfiable Request (only-if-cached)")
代码语言:txt
复制
          .body(EMPTY_RESPONSE)
代码语言:txt
复制
          .sentRequestAtMillis(-1L)
代码语言:txt
复制
          .receivedResponseAtMillis(System.currentTimeMillis())
代码语言:txt
复制
          .build()
代码语言:txt
复制
    }
代码语言:txt
复制
    //不允许使用网络 仅直接使用缓存 对应表格②
代码语言:txt
复制
    // If we don't need the network, we're done.
代码语言:txt
复制
    if (networkRequest == null) {
代码语言:txt
复制
      return cacheResponse!!.newBuilder()
代码语言:txt
复制
          .cacheResponse(stripBody(cacheResponse))
代码语言:txt
复制
          .build()
代码语言:txt
复制
    }
代码语言:txt
复制
    var networkResponse: Response? = null
代码语言:txt
复制
    try {
代码语言:txt
复制
      //使用网络
代码语言:txt
复制
      //对应表格③④
代码语言:txt
复制
      networkResponse = chain.proceed(networkRequest)
代码语言:txt
复制
    } finally {
代码语言:txt
复制
      // If we're crashing on I/O or otherwise, don't leak the cache body.
代码语言:txt
复制
      if (networkResponse == null && cacheCandidate != null) {
代码语言:txt
复制
        cacheCandidate.body?.closeQuietly()
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
     ......缓存新 response
代码语言:txt
复制
   }

我们看完上面的代码 发现所有的缓存策略都是根据networkRequestcacheResponse两个变量进行控制的

接下来我们看一下缓存策略的生成过程

代码语言:txt
复制
fun compute(): CacheStrategy {
代码语言:txt
复制
        class Factory(
代码语言:txt
复制
            private val nowMillis: Long,
代码语言:txt
复制
            internal val request: Request,
代码语言:txt
复制
            private val cacheResponse: Response? //这边的cacheResponse和我们上面讲的还不太一样 这边完全是Cache类中缓存的对象 如果我们之前请求过 并且缓存 则不为null
代码语言:txt
复制
        )
代码语言:txt
复制
       //根据request的cache-control 和response 的cache-control判断
代码语言:txt
复制
      val candidate = computeCandidate()
代码语言:txt
复制
      //使用网络请求 但是请求的request的cache-control是onlyIfCached 表示仅使用缓存
代码语言:txt
复制
      //这就是个悖论了 所以直接返回504 对应表格①
代码语言:txt
复制
      // We're forbidden from using the network and the cache is insufficient.
代码语言:txt
复制
      if (candidate.networkRequest != null && request.cacheControl.onlyIfCached) {
代码语言:txt
复制
        return CacheStrategy(null, null)
代码语言:txt
复制
      }
代码语言:txt
复制
      return candidate
代码语言:txt
复制
    }
代码语言:txt
复制
    private fun computeCandidate(): CacheStrategy {
代码语言:txt
复制
      // No cached response.
代码语言:txt
复制
      //这里的cacheResponse是缓存中命中的  所以如果为null 表示之前没有缓存
代码语言:txt
复制
      if (cacheResponse == null) {
代码语言:txt
复制
        return CacheStrategy(request, null)
代码语言:txt
复制
      }
代码语言:txt
复制
      // Drop the cached response if it's missing a required handshake.
代码语言:txt
复制
      //如果缺少tls握手 直接请求网络
代码语言:txt
复制
      if (request.isHttps && cacheResponse.handshake == null) {
代码语言:txt
复制
        return CacheStrategy(request, null)
代码语言:txt
复制
      }
代码语言:txt
复制
      // If this response shouldn't have been stored, it should never be used as a response source.
代码语言:txt
复制
      // This check should be redundant as long as the persistence store is well-behaved and the
代码语言:txt
复制
      // rules are constant.
代码语言:txt
复制
      //根据cacheResponse的code 判断是否允许cache 
代码语言:txt
复制
      //判断expires是否过期 并且request和reponse的cache-control都是noStore 
代码语言:txt
复制
      //这里就不往下追踪了 感兴趣的同学可以自己阅读一下
代码语言:txt
复制
      if (!isCacheable(cacheResponse, request)) {
代码语言:txt
复制
        return CacheStrategy(request, null)
代码语言:txt
复制
      }
代码语言:txt
复制
        //如果是nocache或者根据If-Modified-Since来判断
代码语言:txt
复制
        //If-Modified-Since会重新请求服务器 然后获取last-modified-since 判断是否修改过
代码语言:txt
复制
      val requestCaching = request.cacheControl
代码语言:txt
复制
      if (requestCaching.noCache || hasConditions(request)) {
代码语言:txt
复制
        return CacheStrategy(request, null)
代码语言:txt
复制
      }
代码语言:txt
复制
      val responseCaching = cacheResponse.cacheControl
代码语言:txt
复制
      val ageMillis = cacheResponseAge()
代码语言:txt
复制
      var freshMillis = computeFreshnessLifetime()
代码语言:txt
复制
      if (requestCaching.maxAgeSeconds != -1) {
代码语言:txt
复制
        freshMillis = minOf(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds.toLong()))
代码语言:txt
复制
      }
代码语言:txt
复制
      var minFreshMillis: Long = 0
代码语言:txt
复制
      if (requestCaching.minFreshSeconds != -1) {
代码语言:txt
复制
        minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds.toLong())
代码语言:txt
复制
      }
代码语言:txt
复制
      var maxStaleMillis: Long = 0
代码语言:txt
复制
      if (!responseCaching.mustRevalidate && requestCaching.maxStaleSeconds != -1) {
代码语言:txt
复制
        maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds.toLong())
代码语言:txt
复制
      }
代码语言:txt
复制
      if (!responseCaching.noCache && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) {
代码语言:txt
复制
        val builder = cacheResponse.newBuilder()
代码语言:txt
复制
        if (ageMillis + minFreshMillis >= freshMillis) {
代码语言:txt
复制
          builder.addHeader("Warning", "110 HttpURLConnection \"Response is stale\"")
代码语言:txt
复制
        }
代码语言:txt
复制
        val oneDayMillis = 24 * 60 * 60 * 1000L
代码语言:txt
复制
        if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) {
代码语言:txt
复制
          builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\"")
代码语言:txt
复制
        }
代码语言:txt
复制
        return CacheStrategy(null, builder.build())
代码语言:txt
复制
      }
代码语言:txt
复制
      // Find a condition to add to the request. If the condition is satisfied, the response body
代码语言:txt
复制
      // will not be transmitted.
代码语言:txt
复制
      val conditionName: String
代码语言:txt
复制
      val conditionValue: String?
代码语言:txt
复制
      when {
代码语言:txt
复制
        etag != null -> {
代码语言:txt
复制
          conditionName = "If-None-Match"
代码语言:txt
复制
          conditionValue = etag
代码语言:txt
复制
        }
代码语言:txt
复制
        lastModified != null -> {
代码语言:txt
复制
          conditionName = "If-Modified-Since"
代码语言:txt
复制
          conditionValue = lastModifiedString
代码语言:txt
复制
        }
代码语言:txt
复制
        servedDate != null -> {
代码语言:txt
复制
          conditionName = "If-Modified-Since"
代码语言:txt
复制
          conditionValue = servedDateString
代码语言:txt
复制
        }
代码语言:txt
复制
         //这里会重新request 然后判断modified-time
代码语言:txt
复制
        else -> return CacheStrategy(request, null) // No condition! Make a regular request.
代码语言:txt
复制
      }
代码语言:txt
复制
      val conditionalRequestHeaders = request.headers.newBuilder()
代码语言:txt
复制
      conditionalRequestHeaders.addLenient(conditionName, conditionValue!!)
代码语言:txt
复制
      val conditionalRequest = request.newBuilder()
代码语言:txt
复制
          .headers(conditionalRequestHeaders.build())
代码语言:txt
复制
          .build()
代码语言:txt
复制
          //直接使用缓存
代码语言:txt
复制
      return CacheStrategy(conditionalRequest, cacheResponse)
代码语言:txt
复制
    }

我们可以根据上面的判断,确定缓存策略

大致是根据cache-control或者handshake是否过期来判断是否需要重新request

例如:

noStore,noCache,If-Modified-Since等等 所有的 cache-

control可以参考这篇

如果在CacheInterceptor中hit cache的话 就不会再往下面的拦截器传递 而是直接原路返回 return response

ConnectInterceptor

作用:负责与服务器连接 这个拦截器的过程分析其实相当复杂undefined 简单来说流程是从连接池中查找连接 如果不存在 就创建连接 并完成TCP,TLS握手undefined 然后等待下一个CallServerInterceptor进行数据的交互

我们分析一下源码 拦截器里的代码真的很少 不过不要被表象欺骗了😌 我第一次看OkHttp源码时 看到这里直接就跳过了

然后分析了CallServerInterceptor源码之后 发现没有获取连接过程

代码语言:txt
复制
 override fun intercept(chain: Interceptor.Chain): Response {
代码语言:txt
复制
    val realChain = chain as RealInterceptorChain
代码语言:txt
复制
    //获取exchange对象 exchange是我们用来和服务端交互的对象封装 看一下initExchange方法
代码语言:txt
复制
    val exchange = realChain.call.initExchange(chain)
代码语言:txt
复制
    val connectedChain = realChain.copy(exchange = exchange)
代码语言:txt
复制
    return connectedChain.proceed(realChain.request)
代码语言:txt
复制
  }

initExchange()中主要会调用ExchangeFinder#find()然后根据下面的调用链

ExchangeFinder#find()->

ExchangeFinder#findHealthyConnection->

ExchangeFinder#findConnection

然后我们看一下findConnection()这个方法内部就实现了connection的查找或创建

前方高能 下面代码会又臭又长😉

代码语言:txt
复制
private fun findConnection(
代码语言:txt
复制
    connectTimeout: Int,
代码语言:txt
复制
    readTimeout: Int,
代码语言:txt
复制
    writeTimeout: Int,
代码语言:txt
复制
    pingIntervalMillis: Int,
代码语言:txt
复制
    connectionRetryEnabled: Boolean
代码语言:txt
复制
  ): RealConnection {
代码语言:txt
复制
    var foundPooledConnection = false
代码语言:txt
复制
    var result: RealConnection? = null
代码语言:txt
复制
    var selectedRoute: Route? = null
代码语言:txt
复制
    var releasedConnection: RealConnection?
代码语言:txt
复制
    val toClose: Socket?
代码语言:txt
复制
    synchronized(connectionPool) {
代码语言:txt
复制
      if (call.isCanceled()) throw IOException("Canceled")
代码语言:txt
复制
      val callConnection = call.connection // changes within this overall method
代码语言:txt
复制
      releasedConnection = callConnection
代码语言:txt
复制
      //如果url不一致或者callConnection为null 就断开链接
代码语言:txt
复制
      toClose = if (callConnection != null && (callConnection.noNewExchanges ||
代码语言:txt
复制
              !sameHostAndPort(callConnection.route().address.url))) {
代码语言:txt
复制
        call.releaseConnectionNoEvents()
代码语言:txt
复制
      } else {
代码语言:txt
复制
        null
代码语言:txt
复制
      }
代码语言:txt
复制
      if (call.connection != null) {
代码语言:txt
复制
        // We had an already-allocated connection and it's good.
代码语言:txt
复制
        //经过判断上面验证 如果不为null 发现当前connection可用 那么就会直接复用connection
代码语言:txt
复制
        result = call.connection
代码语言:txt
复制
        releasedConnection = null
代码语言:txt
复制
      }
代码语言:txt
复制
      if (result == null) {
代码语言:txt
复制
        // The connection hasn't had any problems for this call.
代码语言:txt
复制
        refusedStreamCount = 0
代码语言:txt
复制
        connectionShutdownCount = 0
代码语言:txt
复制
        otherFailureCount = 0
代码语言:txt
复制
        // Attempt to get a connection from the pool.
代码语言:txt
复制
        //第一次试从连接池获取
代码语言:txt
复制
        if (connectionPool.callAcquirePooledConnection(address, call, null, false)) {
代码语言:txt
复制
          foundPooledConnection = true
代码语言:txt
复制
          result = call.connection
代码语言:txt
复制
        } else if (nextRouteToTry != null) {
代码语言:txt
复制
          selectedRoute = nextRouteToTry
代码语言:txt
复制
          nextRouteToTry = null
代码语言:txt
复制
        }
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    toClose?.closeQuietly()
代码语言:txt
复制
    if (releasedConnection != null) {
代码语言:txt
复制
      eventListener.connectionReleased(call, releasedConnection!!)
代码语言:txt
复制
    }
代码语言:txt
复制
    if (foundPooledConnection) {
代码语言:txt
复制
      eventListener.connectionAcquired(call, result!!)
代码语言:txt
复制
    }
代码语言:txt
复制
    if (result != null) {
代码语言:txt
复制
      // If we found an already-allocated or pooled connection, we're done.
代码语言:txt
复制
      return result!!
代码语言:txt
复制
    }
代码语言:txt
复制
    // If we need a route selection, make one. This is a blocking operation.
代码语言:txt
复制
    // 查看是否有新的路由信息
代码语言:txt
复制
    var newRouteSelection = false
代码语言:txt
复制
    if (selectedRoute == null && (routeSelection == null || !routeSelection!!.hasNext())) {
代码语言:txt
复制
      var localRouteSelector = routeSelector
代码语言:txt
复制
      if (localRouteSelector == null) {
代码语言:txt
复制
        localRouteSelector = RouteSelector(address, call.client.routeDatabase, call, eventListener)
代码语言:txt
复制
        this.routeSelector = localRouteSelector
代码语言:txt
复制
      }
代码语言:txt
复制
      newRouteSelection = true
代码语言:txt
复制
      routeSelection = localRouteSelector.next()
代码语言:txt
复制
    }
代码语言:txt
复制
    var routes: List<Route>? = null
代码语言:txt
复制
    synchronized(connectionPool) {
代码语言:txt
复制
      if (call.isCanceled()) throw IOException("Canceled")
代码语言:txt
复制
      if (newRouteSelection) {
代码语言:txt
复制
        // Now that we have a set of IP addresses, make another attempt at getting a connection from
代码语言:txt
复制
        // the pool. This could match due to connection coalescing.
代码语言:txt
复制
        routes = routeSelection!!.routes
代码语言:txt
复制
        // 如果有新的路由 继续从连接池中查找试试
代码语言:txt
复制
        if (connectionPool.callAcquirePooledConnection(address, call, routes, false)) {
代码语言:txt
复制
          foundPooledConnection = true
代码语言:txt
复制
          result = call.connection
代码语言:txt
复制
        }
代码语言:txt
复制
      }
代码语言:txt
复制
      if (!foundPooledConnection) {
代码语言:txt
复制
        if (selectedRoute == null) {
代码语言:txt
复制
          selectedRoute = routeSelection!!.next()
代码语言:txt
复制
        }
代码语言:txt
复制
        // Create a connection and assign it to this allocation immediately. This makes it possible
代码语言:txt
复制
        // for an asynchronous cancel() to interrupt the handshake we're about to do.
代码语言:txt
复制
        result = RealConnection(connectionPool, selectedRoute!!)
代码语言:txt
复制
        connectingConnection = result
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    // If we found a pooled connection on the 2nd time around, we're done.
代码语言:txt
复制
    if (foundPooledConnection) {
代码语言:txt
复制
      eventListener.connectionAcquired(call, result!!)
代码语言:txt
复制
      return result!!
代码语言:txt
复制
    }
代码语言:txt
复制
    // Do TCP + TLS handshakes. This is a blocking operation.
代码语言:txt
复制
    //现在发现可能连接池中没有我们要的connection
代码语言:txt
复制
    //进行TCP和TLS连接
代码语言:txt
复制
    result!!.connect(
代码语言:txt
复制
        connectTimeout,
代码语言:txt
复制
        readTimeout,
代码语言:txt
复制
        writeTimeout,
代码语言:txt
复制
        pingIntervalMillis,
代码语言:txt
复制
        connectionRetryEnabled,
代码语言:txt
复制
        call,
代码语言:txt
复制
        eventListener
代码语言:txt
复制
    )
代码语言:txt
复制
    call.client.routeDatabase.connected(result!!.route())
代码语言:txt
复制
    var socket: Socket? = null
代码语言:txt
复制
    synchronized(connectionPool) {
代码语言:txt
复制
      connectingConnection = null
代码语言:txt
复制
      // Last attempt at connection coalescing, which only occurs if we attempted multiple
代码语言:txt
复制
      // concurrent connections to the same host.
代码语言:txt
复制
      //最后一次尝试从连接池中获取 如果能获取到 就使用连接池中 否则使用连接的connection 并且放入连接池中
代码语言:txt
复制
      if (connectionPool.callAcquirePooledConnection(address, call, routes, true)) {
代码语言:txt
复制
        // We lost the race! Close the connection we created and return the pooled connection.
代码语言:txt
复制
        result!!.noNewExchanges = true
代码语言:txt
复制
        socket = result!!.socket()
代码语言:txt
复制
        result = call.connection
代码语言:txt
复制
        // It's possible for us to obtain a coalesced connection that is immediately unhealthy. In
代码语言:txt
复制
        // that case we will retry the route we just successfully connected with.
代码语言:txt
复制
        nextRouteToTry = selectedRoute
代码语言:txt
复制
      } else {
代码语言:txt
复制
        //放入连接池中
代码语言:txt
复制
        connectionPool.put(result!!)
代码语言:txt
复制
        call.acquireConnectionNoEvents(result!!)
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    socket?.closeQuietly()
代码语言:txt
复制
    eventListener.connectionAcquired(call, result!!)
代码语言:txt
复制
    return result!!
代码语言:txt
复制
  }

上面的注释写的也比较多 流程其实也比较清晰了 我们接下来分析一下 如何从连接池中查找以及如何建立连接

代码语言:txt
复制
//从连接池中获取
代码语言:txt
复制
fun callAcquirePooledConnection(
代码语言:txt
复制
    address: Address,
代码语言:txt
复制
    call: RealCall,
代码语言:txt
复制
    routes: List<Route>?,
代码语言:txt
复制
    requireMultiplexed: Boolean
代码语言:txt
复制
  ): Boolean {
代码语言:txt
复制
    this.assertThreadHoldsLock()
代码语言:txt
复制
    for (connection in connections) {
代码语言:txt
复制
        //判断connection是否支持多路复用
代码语言:txt
复制
      if (requireMultiplexed && !connection.isMultiplexed) continue
代码语言:txt
复制
      //判断connection的host是否匹配
代码语言:txt
复制
      if (!connection.isEligible(address, routes)) continue
代码语言:txt
复制
      call.acquireConnectionNoEvents(connection)
代码语言:txt
复制
      return true
代码语言:txt
复制
    }
代码语言:txt
复制
    return false
代码语言:txt
复制
  }

还有一个TCP和TLS握手流程

代码语言:txt
复制
fun connect(
代码语言:txt
复制
    connectTimeout: Int,
代码语言:txt
复制
    readTimeout: Int,
代码语言:txt
复制
    writeTimeout: Int,
代码语言:txt
复制
    pingIntervalMillis: Int,
代码语言:txt
复制
    connectionRetryEnabled: Boolean,
代码语言:txt
复制
    call: Call,
代码语言:txt
复制
    eventListener: EventListener
代码语言:txt
复制
  ) {
代码语言:txt
复制
    check(protocol == null) { "already connected" }
代码语言:txt
复制
    var routeException: RouteException? = null
代码语言:txt
复制
    val connectionSpecs = route.address.connectionSpecs
代码语言:txt
复制
    val connectionSpecSelector = ConnectionSpecSelector(connectionSpecs)
代码语言:txt
复制
    ......
代码语言:txt
复制
    while (true) {
代码语言:txt
复制
      try {
代码语言:txt
复制
          //注释的意思是 如果是通过HTTP代理HTTPS 那么需要连接Tunnel  
代码语言:txt
复制
          //这里我是在是没看懂什么意思 告辞😞 有知道的大佬可以留言告诉我一下
代码语言:txt
复制
        if (route.requiresTunnel()) {
代码语言:txt
复制
          connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener)
代码语言:txt
复制
          if (rawSocket == null) {
代码语言:txt
复制
            // We were unable to connect the tunnel but properly closed down our resources.
代码语言:txt
复制
            break
代码语言:txt
复制
          }
代码语言:txt
复制
        } else {
代码语言:txt
复制
          //先建立socket连接 包括代理的配置
代码语言:txt
复制
          connectSocket(connectTimeout, readTimeout, call, eventListener)
代码语言:txt
复制
        }
代码语言:txt
复制
        //如果是Http2协议还会创建Http2连接 或者 TLS握手 
代码语言:txt
复制
        //TLS流程大家可以参考一下我之前写的一篇文章
代码语言:txt
复制
        establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener)
代码语言:txt
复制
        eventListener.connectEnd(call, route.socketAddress, route.proxy, protocol)
代码语言:txt
复制
        break
代码语言:txt
复制
      } catch (e: IOException) {
代码语言:txt
复制
        socket?.closeQuietly()
代码语言:txt
复制
        rawSocket?.closeQuietly()
代码语言:txt
复制
        socket = null
代码语言:txt
复制
        rawSocket = null
代码语言:txt
复制
        source = null
代码语言:txt
复制
        sink = null
代码语言:txt
复制
        handshake = null
代码语言:txt
复制
        protocol = null
代码语言:txt
复制
        http2Connection = null
代码语言:txt
复制
        allocationLimit = 1
代码语言:txt
复制
        eventListener.connectFailed(call, route.socketAddress, route.proxy, null, e)
代码语言:txt
复制
        if (routeException == null) {
代码语言:txt
复制
          routeException = RouteException(e)
代码语言:txt
复制
        } else {
代码语言:txt
复制
          routeException.addConnectException(e)
代码语言:txt
复制
        }
代码语言:txt
复制
        if (!connectionRetryEnabled || !connectionSpecSelector.connectionFailed(e)) {
代码语言:txt
复制
          throw routeException
代码语言:txt
复制
        }
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    if (route.requiresTunnel() && rawSocket == null) {
代码语言:txt
复制
      throw RouteException(ProtocolException(
代码语言:txt
复制
          "Too many tunnel connections attempted: $MAX_TUNNEL_ATTEMPTS"))
代码语言:txt
复制
    }
代码语言:txt
复制
    idleAtNs = System.nanoTime()
代码语言:txt
复制
  }

TLS握手流程有疑问的同学 可以看一下我之前写的一篇文章呐

小飞机✈️觉得还可以可以点个赞哦

现在connection就获取完成了 接下来就是与服务器的交互啦

还有创建了新connection之后会putConnectionPool中 其中还有一个clean操作 同学们可以自己看一下代码呐

最后还有一个小点需要说明一下 因为关系到我们下一个拦截器的阅读

在我们最上面的说到 我们会通过ExchangeFinder#find来生成ExchangeCodec对象

首先我们解释一下ExchangeCodec作用okhttp会使用ExchangeCodec封装了与服务器的IO操作

ExchangeCodec的实现类分别对应协议是Http1ExchangeCodecHttp2ExchangeCodec

看一下find方法实现

代码语言:txt
复制
fun find(
代码语言:txt
复制
    client: OkHttpClient,
代码语言:txt
复制
    chain: RealInterceptorChain
代码语言:txt
复制
  ): ExchangeCodec {
代码语言:txt
复制
    try {
代码语言:txt
复制
      val resultConnection = findHealthyConnection(
代码语言:txt
复制
          connectTimeout = chain.connectTimeoutMillis,
代码语言:txt
复制
          readTimeout = chain.readTimeoutMillis,
代码语言:txt
复制
          writeTimeout = chain.writeTimeoutMillis,
代码语言:txt
复制
          pingIntervalMillis = client.pingIntervalMillis,
代码语言:txt
复制
          connectionRetryEnabled = client.retryOnConnectionFailure,
代码语言:txt
复制
          doExtensiveHealthChecks = chain.request.method != "GET"
代码语言:txt
复制
      )
代码语言:txt
复制
      //newCodec方法会对应不同的HTTP协议生成ExchangeCodeC对象
代码语言:txt
复制
      return resultConnection.newCodec(client, chain)
代码语言:txt
复制
    } catch (e: RouteException) {
代码语言:txt
复制
      trackFailure(e.lastConnectException)
代码语言:txt
复制
      throw e
代码语言:txt
复制
    } catch (e: IOException) {
代码语言:txt
复制
      trackFailure(e)
代码语言:txt
复制
      throw RouteException(e)
代码语言:txt
复制
    }
代码语言:txt
复制
  }

Http2

在阅读CallServerInterceptor之前 我们有必要看一下Http2.0相关知识 因为在CallServerInterceptor中会根据不同的Http协议 使用不同的传输方式 我们看一下Http2.0发展的几个阶段

  • HTTP1.x 一个tcp连接只支持一个请求,单向,只能由客户端发起
  • SPDY支持多路复用(Tcp连接复用),header压缩,强制使用Https,服务端推送
  • HTTP2.0 支持明文和加密传输,优化header压缩算法,支持SPDY现有功能,全双工
  • Quic基于UDP实现稳定传输协议 弱网有优化

CallServerInterceptor

作用:负责与服务器进行数据交互

在了解和服务器交互的流程之前 我想先介绍一下okio 这是Square公司开发的一款对java输入输出流的封装框架

JAVA输入输出流真的是非常的复杂 子类繁多 而okio主要分为两个接口SinkSource 分别对应输出和输入相关

接下来我们看一下实现代码 流程也比较简单 就是发送请求+获取响应

代码语言:txt
复制
 @Throws(IOException::class)
代码语言:txt
复制
  override fun intercept(chain: Interceptor.Chain): Response {
代码语言:txt
复制
    val realChain = chain as RealInterceptorChain
代码语言:txt
复制
    val exchange = realChain.exchange!!
代码语言:txt
复制
    val request = realChain.request
代码语言:txt
复制
    val requestBody = request.body
代码语言:txt
复制
    val sentRequestMillis = System.currentTimeMillis()
代码语言:txt
复制
    //将header写入socket
代码语言:txt
复制
    exchange.writeRequestHeaders(request)
代码语言:txt
复制
    var invokeStartEvent = true
代码语言:txt
复制
    var responseBuilder: Response.Builder? = null
代码语言:txt
复制
    if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
代码语言:txt
复制
      // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
代码语言:txt
复制
      // Continue" response before transmitting the request body. If we don't get that, return
代码语言:txt
复制
      // what we did get (such as a 4xx response) without ever transmitting the request body.
代码语言:txt
复制
      if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
代码语言:txt
复制
        exchange.flushRequest()
代码语言:txt
复制
        responseBuilder = exchange.readResponseHeaders(expectContinue = true)
代码语言:txt
复制
        exchange.responseHeadersStart()
代码语言:txt
复制
        invokeStartEvent = false
代码语言:txt
复制
      }
代码语言:txt
复制
      if (responseBuilder == null) {
代码语言:txt
复制
        //如果支持复用 传输request body
代码语言:txt
复制
        if (requestBody.isDuplex()) {
代码语言:txt
复制
          // Prepare a duplex body so that the application can send a request body later.
代码语言:txt
复制
          exchange.flushRequest()
代码语言:txt
复制
          val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
代码语言:txt
复制
          requestBody.writeTo(bufferedRequestBody)
代码语言:txt
复制
        } else {
代码语言:txt
复制
          // Write the request body if the "Expect: 100-continue" expectation was met.
代码语言:txt
复制
          val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
代码语言:txt
复制
          requestBody.writeTo(bufferedRequestBody)
代码语言:txt
复制
          bufferedRequestBody.close()
代码语言:txt
复制
        }
代码语言:txt
复制
      } else {
代码语言:txt
复制
        exchange.noRequestBody()
代码语言:txt
复制
        if (!exchange.connection.isMultiplexed) {
代码语言:txt
复制
          // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
代码语言:txt
复制
          // from being reused. Otherwise we're still obligated to transmit the request body to
代码语言:txt
复制
          // leave the connection in a consistent state.
代码语言:txt
复制
          exchange.noNewExchangesOnConnection()
代码语言:txt
复制
        }
代码语言:txt
复制
      }
代码语言:txt
复制
    } else {
代码语言:txt
复制
      exchange.noRequestBody()
代码语言:txt
复制
    }
代码语言:txt
复制
    //request完成
代码语言:txt
复制
    if (requestBody == null || !requestBody.isDuplex()) {
代码语言:txt
复制
      exchange.finishRequest()
代码语言:txt
复制
    }
代码语言:txt
复制
    //获取reponse header
代码语言:txt
复制
    if (responseBuilder == null) {
代码语言:txt
复制
      responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
代码语言:txt
复制
      if (invokeStartEvent) {
代码语言:txt
复制
        exchange.responseHeadersStart()
代码语言:txt
复制
        invokeStartEvent = false
代码语言:txt
复制
      }
代码语言:txt
复制
    }
代码语言:txt
复制
    var response = responseBuilder
代码语言:txt
复制
        .request(request)
代码语言:txt
复制
        .handshake(exchange.connection.handshake())
代码语言:txt
复制
        .sentRequestAtMillis(sentRequestMillis)
代码语言:txt
复制
        .receivedResponseAtMillis(System.currentTimeMillis())
代码语言:txt
复制
        .build()
代码语言:txt
复制
    var code = response.code
代码语言:txt
复制
    if (code == 100) {
代码语言:txt
复制
      // Server sent a 100-continue even though we did not request one. Try again to read the actual
代码语言:txt
复制
      // response status.
代码语言:txt
复制
      //100表示继续获取
代码语言:txt
复制
      responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
代码语言:txt
复制
      if (invokeStartEvent) {
代码语言:txt
复制
        exchange.responseHeadersStart()
代码语言:txt
复制
      }
代码语言:txt
复制
      response = responseBuilder
代码语言:txt
复制
          .request(request)
代码语言:txt
复制
          .handshake(exchange.connection.handshake())
代码语言:txt
复制
          .sentRequestAtMillis(sentRequestMillis)
代码语言:txt
复制
          .receivedResponseAtMillis(System.currentTimeMillis())
代码语言:txt
复制
          .build()
代码语言:txt
复制
      code = response.code
代码语言:txt
复制
    }
代码语言:txt
复制
    exchange.responseHeadersEnd(response)
代码语言:txt
复制
    response = if (forWebSocket && code == 101) {
代码语言:txt
复制
      // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
代码语言:txt
复制
      response.newBuilder()
代码语言:txt
复制
          .body(EMPTY_RESPONSE)
代码语言:txt
复制
          .build()
代码语言:txt
复制
    } else {
代码语言:txt
复制
      //获取response body
代码语言:txt
复制
      response.newBuilder()
代码语言:txt
复制
          .body(exchange.openResponseBody(response))
代码语言:txt
复制
          .build()
代码语言:txt
复制
    }
代码语言:txt
复制
    if ("close".equals(response.request.header("Connection"), ignoreCase = true) ||
代码语言:txt
复制
        "close".equals(response.header("Connection"), ignoreCase = true)) {
代码语言:txt
复制
      exchange.noNewExchangesOnConnection()
代码语言:txt
复制
    }
代码语言:txt
复制
    if ((code == 204 || code == 205) && response.body?.contentLength() ?: -1L > 0L) {
代码语言:txt
复制
      throw ProtocolException(
代码语言:txt
复制
          "HTTP $code had non-zero Content-Length: ${response.body?.contentLength()}")
代码语言:txt
复制
    }
代码语言:txt
复制
    return response
代码语言:txt
复制
  }

上面的代码 流程也比较简单 就是request+response

我们分析一下分析一下写入Request流程

ExchangeCodec#writeRequestHeaders(request)

传输头部在HTTP1.x和HTTP2.0有点区别,HTTP1.x就直接将header通过写入Sink

Buffer,而HTTP2.0会先创建http2Connection.newStream()对象

代码语言:txt
复制
@Synchronized @Throws(IOException::class)
代码语言:txt
复制
  fun headers(
代码语言:txt
复制
    outFinished: Boolean,
代码语言:txt
复制
    streamId: Int,
代码语言:txt
复制
    headerBlock: List<Header>
代码语言:txt
复制
  ) {
代码语言:txt
复制
    if (closed) throw IOException("closed")
代码语言:txt
复制
    //Hpack压缩算法 将压缩后数据存入hpackBuffer
代码语言:txt
复制
    hpackWriter.writeHeaders(headerBlock)
代码语言:txt
复制
    val byteCount = hpackBuffer.size
代码语言:txt
复制
    val length = minOf(maxFrameSize.toLong(), byteCount)
代码语言:txt
复制
    var flags = if (byteCount == length) FLAG_END_HEADERS else 0
代码语言:txt
复制
    if (outFinished) flags = flags or FLAG_END_STREAM
代码语言:txt
复制
    //HTTP2.0特性 帧传输
代码语言:txt
复制
    frameHeader(
代码语言:txt
复制
        streamId = streamId,
代码语言:txt
复制
        length = length.toInt(),
代码语言:txt
复制
        type = TYPE_HEADERS,
代码语言:txt
复制
        flags = flags
代码语言:txt
复制
    )
代码语言:txt
复制
    sink.write(hpackBuffer, length)
代码语言:txt
复制
    if (byteCount > length) writeContinuationFrames(streamId, byteCount - length)
代码语言:txt
复制
  }

这里有两个可以HTTP2.0特性可以关注一下

  • HPACK压缩
  • 传输帧

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 请求方式
  • enqueue()
  • RealCall.executeOn()
  • getResponseWithInterceptorChain()
  • RetryAndFollowUpInterceptor
  • BridgeInterceptor
  • CacheInterceptor
  • ConnectInterceptor
  • Http2
  • CallServerInterceptor
    • ExchangeCodec#writeRequestHeaders(request)
    相关产品与服务
    SSL 证书
    腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档