OkHttp(三)

前两篇文章,讲述了OkHttp的根底的应用与申请的调度状况,而明天就让咱们来看看OkHttp的精华之一-责任链模式。

责任链模式

后面的文章中咱们看到,当理论进行网络申请时,无论是同步申请还是异步申请都会应用getResponseWithInterceptorChain() 这个办法,所以咱们先从这个办法开始钻研。

  fun getResponseWithInterceptorChain(): Response {    // Build a full stack of interceptors.    // 增加各种拦截器 这个前面逐个介绍    val interceptors = mutableListOf<Interceptor>()    // 自定义的一个拦截器    interceptors += client.interceptors    // 零碎内置的拦截器    interceptors += RetryAndFollowUpInterceptor(client)    interceptors += BridgeInterceptor(client.cookieJar)    interceptors += CacheInterceptor(client.cache)    interceptors += ConnectInterceptor    if (!forWebSocket) {      interceptors += client.networkInterceptors    }    interceptors += CallServerInterceptor(forWebSocket)        // 创立责任链    val chain = RealInterceptorChain(interceptors, transmitter, null, 0, originalRequest, this,        client.connectTimeoutMillis, client.readTimeoutMillis, client.writeTimeoutMillis)    var calledNoMoreExchanges = false    try {      // 执行责任链      val response = chain.proceed(originalRequest)      if (transmitter.isCanceled) {        response.closeQuietly()        throw IOException("Canceled")      }      return response    } catch (e: IOException) {      calledNoMoreExchanges = true      throw transmitter.noMoreExchanges(e) as Throwable    } finally {      if (!calledNoMoreExchanges) {        transmitter.noMoreExchanges(null)      }    }  }

咱们能够看到,该办法中将拦截器逐个增加汇合中,并创立了一个责任链,用chain.proceed()办法来执行申请。

OkHttp采纳责任链的模式来使每个性能离开,每个Interceptor自行实现本人的工作,并且将不属于本人的工作交给下一个,简化了各自的责任和逻辑。

接下来看看proceed的办法

 override fun proceed(request: Request): Response {    return proceed(request, transmitter, exchange)  }  @Throws(IOException::class)  fun proceed(request: Request, transmitter: Transmitter, exchange: Exchange?): Response {    if (index >= interceptors.size) throw AssertionError()    calls++    ...        // 获取下一个拦截器,链中的拦截器汇合index+1    // Call the next interceptor in the chain.    val next = RealInterceptorChain(interceptors, transmitter, exchange,        index + 1, request, call, connectTimeout, readTimeout, writeTimeout)    val interceptor = interceptors[index]    @Suppress("USELESS_ELVIS")    // 执行以后的拦截器-如果在配置okhttpClient,时没有设置intercept默认是先执行:retryAndFollowUpInterceptor 拦截器`    val response = interceptor.intercept(next) ?: throw NullPointerException(        "interceptor $interceptor returned null")    ...    return response  }

在该办法中咱们能够看到递归调用了下一个拦截器,当所有拦截器调用结束后,返回咱们所得的Response。每个拦截器都重写了intercept()办法,用以执行申请。

责任链的一个执行过程如下图

接下来让咱们剖析默认责任链的一个作用,并作出一些源码剖析。

RetryAndFollowUpInterceptor

其创立过程是在 构建newCall对象时

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {    this.client = client;    this.originalRequest = originalRequest;    this.forWebSocket = forWebSocket;    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);  }  ...  @Override public Call newCall(Request request) {    return RealCall.newRealCall(this, request, false /* for web socket */);  }

简略看一下应用的过程
首先创立了transmitter对象,他封装了网络申请相干的信息:连接池,地址信息,网络申请,事件回调,负责网络连接的连贯、敞开,开释等操作。

    var request = chain.request()    val realChain = chain as RealInterceptorChain    val transmitter = realChain.transmitter()

而后则进入了网络连接的循环

    //计数器 屡次相应的次数是由限度的,不同浏览器举荐的次数不同,还特别强调了HTTP 1.0协定举荐5次。    var followUpCount = 0    var priorResponse: Response? = null    while (true) {      //筹备连贯      transmitter.prepareToConnect(request)      if (transmitter.isCanceled) {        throw IOException("Canceled")      }      var response: Response      var success = false      try {        // 失去最终的后果        response = realChain.proceed(request, transmitter, null)        success = true      } catch (e: RouteException) {        // The attempt to connect via a route failed. The request will not have been sent.        //连贯地址的异样,判断是否能可能复原,也就是是否要重试        if (!recover(e.lastConnectException, transmitter, false, request)) {          throw e.firstConnectException        }        continue      } catch (e: IOException) {        // An attempt to communicate with a server failed. The request may have been sent.        // 连贯服务器的异样 判断网络申请是否曾经开始        val requestSendStarted = e !is ConnectionShutdownException        // 同上        if (!recover(e, transmitter, requestSendStarted, request)) throw e        continue      } finally {        // The network call threw an exception. Release any resources.        // 开释资源        if (!success) {          transmitter.exchangeDoneDueToException()        }      }      // Attach the prior response if it exists. Such responses never have a body.      //如果不为空保留到Response中      if (priorResponse != null) {        response = response.newBuilder()            .priorResponse(priorResponse.newBuilder()                .body(null)                .build())            .build()      }      val exchange = response.exchange      val route = exchange?.connection()?.route()      // 判断返回后果response,是否须要持续欠缺申请,例如证书验证等等      val followUp = followUpRequest(response, route)            // 如果不须要持续欠缺网络申请,返回response      if (followUp == null) {        if (exchange != null && exchange.isDuplex) {          transmitter.timeoutEarlyExit()        }        return response      }            // 如果body内容只能发送一次 间接放回      val followUpBody = followUp.body      if (followUpBody != null && followUpBody.isOneShot()) {        return response      }      response.body?.closeQuietly()      if (transmitter.hasExchange()) {        exchange?.detachWithViolence()      }            // 如果曾经超过最大的网络申请追加数,开释连贯,抛出协定异样      if (++followUpCount > MAX_FOLLOW_UPS) {        throw ProtocolException("Too many follow-up requests: $followUpCount")      }      // 更新下一次的网络申请对象      request = followUp      // 保留上一次的申请后果      priorResponse = response    }

而后就是重试阶段recover()的源码了

  /**   * Report and attempt to recover from a failure to communicate with a server. Returns true if   * `e` is recoverable, or false if the failure is permanent. Requests with a body can only   * be recovered if the body is buffered or if the failure occurred before the request has been   * sent.   */  private fun recover(    e: IOException,    transmitter: Transmitter,    requestSendStarted: Boolean,    userRequest: Request  ): Boolean {    // The application layer has forbidden retries.    // 设置了不须要重试    if (!client.retryOnConnectionFailure) return false    // We can't send the request body again.    // body内容只能发送一次    if (requestSendStarted && requestIsOneShot(e, userRequest)) return false    // This exception is fatal.    // 判断异样类型,是否要持续尝试,    // 不会重试的类型:协定异样、Socketet异样并且网络状况还没开始,ssl认证异样    if (!isRecoverable(e, requestSendStarted)) return false    // No more routes to attempt.    // 曾经没有其余可用的路由地址了    if (!transmitter.canRetry()) return false    // For failure recovery, use the same route selector with a new connection.    // 其余放回true    return true  }

咱们略微屡一下下面源码的流程:

  • 首先应用了transmitter对象(重要),用以提供相应的网络连接相干的货色
  • 而后开始连贯,而后又有着几种状况

    • 连贯胜利,且无后续操作(如认证等),间接放回
    • 连贯胜利,且有后续操作,则进入下一次循环
    • 连贯失败,RouteException和IOException异样,利用recover()判断是否重试,不要重试则开释资源,要重试则continue;
    • 连贯胜利,然而重试的次数超过限度,则有问题(能够本人创立拦截器来批改重试次数)。

BridgeIntecepter

这个拦截器的性能较为的简略,申请之前对响应头做了一些查看,并增加一些头,而后在申请之后对响应做一些解决(gzip解压or设置cookie)。

还是让咱们看一下源码。

  override fun intercept(chain: Interceptor.Chain): Response {    val userRequest = chain.request()    val requestBuilder = userRequest.newBuilder()        // 如果咱们有RequestBody,会写一些header信息,如内容长度和内容类型等    val body = userRequest.body    if (body != null) {      ...    }        // 对一些必要的属性进行补充    if (userRequest.header("Host") == null) {      requestBuilder.header("Host", userRequest.url.toHostHeader())    }    if (userRequest.header("Connection") == null) {      requestBuilder.header("Connection", "Keep-Alive")    }    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing    // the transfer stream.    // 默认的编码格局gzip    var transparentGzip = false    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {      transparentGzip = true      requestBuilder.header("Accept-Encoding", "gzip")    }        // 把之前的cookie存在header里    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)    }        // 失去Response    val networkResponse = chain.proceed(requestBuilder.build())        // 保留新的cookie    cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)    val responseBuilder = networkResponse.newBuilder()        .request(userRequest)        // 如果应用的gzip编码,并且返回的response有body信息,对做相应的解决    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()        responseBuilder.headers(strippedHeaders)        val contentType = networkResponse.header("Content-Type")        responseBuilder.body(RealResponseBody(contentType, -1L, gzipSource.buffer()))      }    }    return responseBuilder.build()  }

CacheIntecepter

在看这个拦截器的源码之前,咱们还得关注一件事件,OkHttp的缓存是怎么缓存的呢?

OkHttp中的Cache类,采纳了DiskLruCache,外部应用最近起码应用算法,优先淘汰最近工夫内起码次应用的缓存对象,它只有硬存缓存,并没有内存缓存,这是他缓存机制的一大缺点,当然咱们能够通过自定义缓存机制来解决这一问题。

在OkHttp中还存在一个缓存策略CacheStrategy
CacheStrategy的外部工厂类Factory中有一个getCandidate办法,会依据理论的申请生成对应的CacheStrategy类返回,是个典型的简略工厂模式。其外部保护一个request和response,通过指定request和response来通知CacheInterceptor是应用缓存还是应用网络申请,亦或两者同时应用。

理解完之后,咱们来看源码:

  override fun intercept(chain: Interceptor.Chain): Response {    1.如果设置缓存并且以后request有缓存,则从缓存Cache中获取以后申请request的缓存response    val cacheCandidate = cache?.get(chain.request())    val now = System.currentTimeMillis()        // 2.传入的申请request和获取的缓存response通过缓存策略对象CacheStragy的工厂类get办法依据一些规定获取缓存策略CacheStrategy    //(这里的规定依据申请的request和缓存的Response的header头部信息生成的,比方是否有noCache标记位,是否是immutable不可变,缓存是否过期等等)    val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()    // 3.生成的CacheStrategy有2个变量,networkRequest和cacheRequest,如果networkRequest为Null示意不进行网络申请,如果cacheResponse为null,则示意没有无效缓存     val networkRequest = strategy.networkRequest    val cacheResponse = strategy.cacheResponse    cache?.trackResponse(strategy)        // 4.缓存不可用,敞开    if (cacheCandidate != null && cacheResponse == null) {      // The cache candidate wasn't applicable. Close it.      cacheCandidate.body?.closeQuietly()    }    // If we're forbidden from using the network and the cache is insufficient, fail.    // 5.如果networkRequest和cacheResponse都为Null,则示意不申请网络且缓存为null,返回504,申请失败    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()    }    // If we don't need the network, we're done.    // 6.如果不申请网络,但存在缓存,则不申请网络,间接返回缓存,完结,不执行下一个拦截器    if (networkRequest == null) {      return cacheResponse!!.newBuilder()          .cacheResponse(stripBody(cacheResponse))          .build()    }        // 7.否则,申请网络,并调用下一个拦截器链,将申请转发到下一个拦截器    var networkResponse: Response? = null    try {      networkResponse = chain.proceed(networkRequest)    } finally {      // If we're crashing on I/O or otherwise, don't leak the cache body.      if (networkResponse == null && cacheCandidate != null) {        cacheCandidate.body?.closeQuietly()      }    }        //8.申请网络,并且网络申请返回HTTP_NOT_MODIFIED,阐明缓存无效,则合并网络响应和缓存后果,同时更新缓存    // If we have a cache response too, then we're doing a conditional get.    if (cacheResponse != null) {      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()        // Update the cache after combining headers but before stripping the        // Content-Encoding header (as performed by initContentStream()).        cache!!.trackConditionalCacheHit()        cache.update(cacheResponse, response)        return response      } else {        cacheResponse.body?.closeQuietly()      }    }        //9.若没有缓存,则写入缓存    val response = networkResponse!!.newBuilder()        .cacheResponse(stripBody(cacheResponse))        .networkResponse(stripBody(networkResponse))        .build()    if (cache != null) {      if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {        // Offer this request to the cache.        val cacheRequest = cache.put(response)        return cacheWritingResponse(cacheRequest, response)      }      // 如果申请的办法不须要缓存,移除缓存,例如post,put      if (HttpMethod.invalidatesCache(networkRequest.method)) {        try {          cache.remove(networkRequest)        } catch (_: IOException) {          // The cache cannot be written.        }      }    }    return response  }

让咱们简略梳理一下缓存流程

  • 从以后的Request中获取缓存,看是否有缓存
  • 非网络申请时,需联合是否有缓存进行判断,如果有缓存,间接返回;如果没有缓存,放回504
  • 是网络申请时,如果放回304,则做一个小的修补即可;否则依据缓存策略来判断是否要更新缓存(个别要)。

ConnectIntecepter(外围)

获取连贯这个过程较为简单,尽力来梳理这个过程。

首先咱们间接来看这个类的源码,不难发现这个类的源码较为简单,次要外围是transmitter的办法。

override fun intercept(chain: Interceptor.Chain): Response {    val realChain = chain as RealInterceptorChain    val request = realChain.request()    val transmitter = realChain.transmitter()    // We need the network to satisfy this request. Possibly for validating a conditional GET.    val doExtensiveHealthChecks = request.method != "GET"        // 利用重试的责任链生成的transmitter类 来获取连贯    val exchange = transmitter.newExchange(chain, doExtensiveHealthChecks)    return realChain.proceed(request, transmitter, exchange)  }

而后咱们来看看这个类,transmitter

/** Returns a new exchange to carry a new request and response. */  internal fun newExchange(chain: Interceptor.Chain, doExtensiveHealthChecks: Boolean): Exchange {    ...//做一些查看           // 获取连贯 调配一个Connection和HttpCodec,为最终的申请做筹备    val codec = exchangeFinder!!.find(client, chain, doExtensiveHealthChecks)    val result = Exchange(this, call, eventListener, exchangeFinder!!, codec)    ...  }
  fun find(    client: OkHttpClient,    chain: Interceptor.Chain,    doExtensiveHealthChecks: Boolean  ): ExchangeCodec {    val connectTimeout = chain.connectTimeoutMillis()    val readTimeout = chain.readTimeoutMillis()    val writeTimeout = chain.writeTimeoutMillis()    val pingIntervalMillis = client.pingIntervalMillis    val connectionRetryEnabled = client.retryOnConnectionFailure    try {      // 获取连贯      val resultConnection = findHealthyConnection(          connectTimeout = connectTimeout,          readTimeout = readTimeout,          writeTimeout = writeTimeout,          pingIntervalMillis = pingIntervalMillis,          connectionRetryEnabled = connectionRetryEnabled,          doExtensiveHealthChecks = doExtensiveHealthChecks      )      // 设置编码,有Http1codec和Http2codec两种形式 后者能够复用连贯      return resultConnection.newCodec(client, chain)    } catch (e: RouteException) {      trackFailure()      throw e    } catch (e: IOException) {      trackFailure()      throw RouteException(e)    }
  // 获取连贯  @Throws(IOException::class)  private fun findHealthyConnection(    connectTimeout: Int,    readTimeout: Int,    writeTimeout: Int,    pingIntervalMillis: Int,    connectionRetryEnabled: Boolean,    doExtensiveHealthChecks: Boolean  ): RealConnection {    while (true) {      // 查找新连贯      val candidate = findConnection(          connectTimeout = connectTimeout,          readTimeout = readTimeout,          writeTimeout = writeTimeout,          pingIntervalMillis = pingIntervalMillis,          connectionRetryEnabled = connectionRetryEnabled      )      // If this is a brand new connection, we can skip the extensive health checks.      // 如果是新连贯 则间接应用      synchronized(connectionPool) {        if (candidate.successCount == 0) {          return candidate        }      }      // Do a (potentially slow) check to confirm that the pooled connection is still good. If it      // isn't, take it out of the pool and start again.      //判断连接池中连贯是否可用,如果不可用,则开释该连贯并从连接池中移除,并持续寻找可用连贯      if (!candidate.isHealthy(doExtensiveHealthChecks)) {        candidate.noNewExchanges()        continue      }      return candidate    }  }

接着就是正式获取连贯这一步了,咱们从正文中能够看到,首先从曾经存在的Connection来选取连贯,而后从连接池中寻找,最初才是新建连贯。

  /**   * Returns a connection to host a new stream. This prefers the existing connection if it exists,   * then the pool, finally building a new connection.   */  @Throws(IOException::class)  private fun findConnection(    connectTimeout: Int,    readTimeout: Int,    writeTimeout: Int,    pingIntervalMillis: Int,    connectionRetryEnabled: Boolean  ): RealConnection {    var foundPooledConnection = false    var result: RealConnection? = null    var selectedRoute: Route? = null    var releasedConnection: RealConnection?    val toClose: Socket?    synchronized(connectionPool) {      if (transmitter.isCanceled) throw IOException("Canceled")      hasStreamFailure = false // This is a fresh attempt.·           // 对现有连贯做一个备份      releasedConnection = transmitter.connection      toClose = if (transmitter.connection != null && transmitter.connection!!.noNewExchanges) {        // 失去要敞开的连贯的socket        transmitter.releaseConnectionNoEvents()      } else {        null      }            // 如果能够应用 则应用      if (transmitter.connection != null) {        // We had an already-allocated connection and it's good.        result = transmitter.connection        releasedConnection = null      }            // 如果没有能够用的连贯,从连接池中查找      if (result == null) {        // Attempt to get a connection from the pool.        // 以URL为key查找        if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {          foundPooledConnection = true          result = transmitter.connection        } else if (nextRouteToTry != null) {          selectedRoute = nextRouteToTry          nextRouteToTry = null        } else if (retryCurrentRoute()) {          selectedRoute = transmitter.connection!!.route() // 应用路由地址,能够是代理地址        }      }    }    // 敞开之前的socket    toClose?.closeQuietly()    ... // 如果下面找到,间接返回    if (result != null) {      // If we found an already-allocated or pooled connection, we're done.      return result!!    }        // If we need a route selection, make one. This is a blocking operation.    var newRouteSelection = false    // 抉择一个不空的路由    if (selectedRoute == null && (routeSelection == null || !routeSelection!!.hasNext())) {      newRouteSelection = true      routeSelection = routeSelector.next()    }    var routes: List<Route>? = null    synchronized(connectionPool) {      if (transmitter.isCanceled) throw IOException("Canceled")      if (newRouteSelection) {        // Now that we have a set of IP addresses, make another attempt at getting a connection from        // the pool. This could match due to connection coalescing.        routes = routeSelection!!.routes               // 依据IP地址和Route从连接池进行第二次查找        if (connectionPool.transmitterAcquirePooledConnection(                address, transmitter, routes, false)) {          foundPooledConnection = true          result = transmitter.connection        }      }      if (!foundPooledConnection) {        if (selectedRoute == null) {          selectedRoute = routeSelection!!.next()        }        // 如果没有找到,再应用下一个路由汇合        // Create a connection and assign it to this allocation immediately. This makes it possible        // for an asynchronous cancel() to interrupt the handshake we're about to do.        result = RealConnection(connectionPool, selectedRoute!!)        connectingConnection = result      }    }    // If we found a pooled connection on the 2nd time around, we're done.    if (foundPooledConnection) {      eventListener.connectionAcquired(call, result!!)      return result!!    }        // 到这里还没找到连贯,那就去创立这个连贯    // Do TCP + TLS handshakes. This is a blocking operation.    result!!.connect(        connectTimeout,        readTimeout,        writeTimeout,        pingIntervalMillis,        connectionRetryEnabled,        call,        eventListener    )    connectionPool.routeDatabase.connected(result!!.route())    var socket: Socket? = null    synchronized(connectionPool) {      connectingConnection = null      // Last attempt at connection coalescing, which only occurs if we attempted multiple      // concurrent connections to the same host.      // 如果result连贯是http2.0连贯,http2.0反对一个连贯同时发动多个申请,这里做去重判断,避免创立多个      if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) {        // We lost the race! Close the connection we created and return the pooled connection.        result!!.noNewExchanges = true        socket = result!!.socket()        result = transmitter.connection        // It's possible for us to obtain a coalesced connection that is immediately unhealthy. In        // that case we will retry the route we just successfully connected with.        nextRouteToTry = selectedRoute      } else {        connectionPool.put(result!!)        transmitter.acquireConnectionNoEvents(result!!)      }    }    socket?.closeQuietly()    eventListener.connectionAcquired(call, result!!)    return result!!

在这个源码中,呈现了几个新的类,路由route类,地址address类,咱们简略的来看看这两个类,
Address:封装了所有的能够拜访的地址信息,在这个类中还增加了代理和dns的相干信息(在OkHttpClient中设置好)proxySelector能够为一个URI设置多个代理,如果地址连贯失败还回调connectFailed;proxy设置独自的全局代理,他的优先级高于proxySelecttor;dns用法和proxySelecttor相似,能够返回多个地址。

private Address createAddress(HttpUrl url) {        SSLSocketFactory sslSocketFactory = null;        HostnameVerifier hostnameVerifier = null;        CertificatePinner certificatePinner = null;        if (url.isHttps()) {            sslSocketFactory = client.sslSocketFactory();            hostnameVerifier = client.hostnameVerifier();            certificatePinner = client.certificatePinner();        }         return new Address(url.host(), url.port(), client.dns(), client.socketFactory(),                sslSocketFactory, hostnameVerifier, certificatePinner, client.proxyAuthenticator(),                client.proxy(), client.protocols(), client.connectionSpecs(), client.proxySelector());    }

Route路由:对地址Adress的一个封装类
RouteSelector路由选择器:在OKhttp中其实其作用也就是返回一个可用的Route对象

咱们来大略梳理一下流程

  • 首先对以后的流进行一个初步判断,满足则复用
  • 不满足则,对连接池进行第一次的查找,此次查找中,route类为空
connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)

查找失去间接复用

  • 查找不到则应用路由进行查找,查找设置的代理和DNS是否能找到相干的代理,如果找到则复用
connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, false)
  • 上述路线都查找不到,间接新建一个连贯,放入连接池中,并把解析的host等信息保留到Connection中,不便下次复用。其中还要多做一步判断,如果是HTTP2同时发动的申请,要进行一个去重的操作。

下图是一个简要的连贯步骤。

CallServerInterceptor

  • 首先取得后面Intecepter获取的信息
  • 而后利用编码器写入header信息
  exchange.writeRequestHeaders(request)
  • 判断是否要发送申请体,有申请体时,但冀望返回状态码是100时,则不发送。否则利用流封装后发送。
  var responseBuilder: Response.Builder? = null    if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {      // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100      // Continue" response before transmitting the request body. If we don't get that, return      // what we did get (such as a 4xx response) without ever transmitting the request body.      if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {        exchange.flushRequest()        responseHeadersStarted = true        exchange.responseHeadersStart()        responseBuilder = exchange.readResponseHeaders(true)      }      if (responseBuilder == null) {        if (requestBody.isDuplex()) {          // Prepare a duplex body so that the application can send a request body later.          exchange.flushRequest()          val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()          requestBody.writeTo(bufferedRequestBody)        } else {          // Write the request body if the "Expect: 100-continue" expectation was met.          val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()          requestBody.writeTo(bufferedRequestBody)          bufferedRequestBody.close()        }      } else {        exchange.noRequestBody()        if (!exchange.connection()!!.isMultiplexed) {          // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection          // from being reused. Otherwise we're still obligated to transmit the request body to          // leave the connection in a consistent state.          exchange.noNewExchangesOnConnection()        }      }    } else {      exchange.noRequestBody()    }
// 创立response,把握手信息,和request等信息保留进去@Override public Response intercept(Chain chain) throws IOException {    ...    // 写入request完结    httpCodec.finishRequest();    if (responseBuilder == null) {      realChain.eventListener().responseHeadersStart(realChain.call());      // 读取相应response的header信息      responseBuilder = httpCodec.readResponseHeaders(false);    }     // 创立response,把握手信息,和request等信息保留进去    Response response = responseBuilder        .request(request)        .handshake(streamAllocation.connection().handshake())        .sentRequestAtMillis(sentRequestMillis)        .receivedResponseAtMillis(System.currentTimeMillis())        .build();    // 开始判断申请码    int code = response.code();    if (code == 100) {      // 如果是100,间接读取header      responseBuilder = httpCodec.readResponseHeaders(false);      response = responseBuilder              .request(request)              // 握手              .handshake(streamAllocation.connection().handshake())              .sentRequestAtMillis(sentRequestMillis)              .receivedResponseAtMillis(System.currentTimeMillis())              .build();       code = response.code();    }    ...    // 判断申请码    if (forWebSocket && code == 101) {      // 客户端须要转换协定,这里须要设置一个空的response      response = response.newBuilder()          .body(Util.EMPTY_RESPONSE)          .build();    } else {      // 读取网络的body      response = response.newBuilder()          .body(httpCodec.openResponseBody(response))          .build();    }    // 如果header申请敞开连贯    if ("close".equalsIgnoreCase(response.request().header("Connection"))        || "close".equalsIgnoreCase(response.header("Connection"))) {      // 敞开这个链接      streamAllocation.noNewStreams();    }    // 非凡code判断    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {      throw new ProtocolException(          "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());    }     return response;  }

如果想要理解具体的读取和写入流程,以我当初应用的Http 2.0为例:
连贯:Http2Connection;
流:Http2Stream;
编解码器:Http2Codec;
读操作:Http2Reader;
写操作:Http2Writer;
他们之间的关系:
1、Http2Connection调用Http2Reader和Http2Writer来进行读写;
2、Http2Stream调用Http2Connection进行读写;
3、Http2Codec调用Http2Connection和Http2Stream进行操作;

总结

咱们分三个阶段来简要介绍了OkHttp这个框架,因为当初程度无限,所以会存在疏漏。当前有些有新的发现,则再对其进行补充。