zoukankan      html  css  js  c++  java
  • 腾讯面试官:OkHttp 用了那么久,你知道原理吗?

    很多朋友反映大厂的面试喜欢挖底层知识,像OkHttp这些都是必问的问题。这里就给大家分享一篇非常有帮助的技术文吧。

    HTTP是现代应用程序网络的方式。这就是我们交换数据和媒体的方式。有效地执行HTTP可以使您的内容加载更快并节省带宽。
    原文地址:https://blog.csdn.net/qq_40861368/article/details/115832703

    OkHttp是一个高效的HTTP库:

    • 支持HTTP / 2,允许对同一主机的所有请求共享一个套接字
    • 通过连接池可减少请求延迟(如果HTTP / 2不可用)
    • 支持GZIP压缩减少数据流量
    • 响应缓存可以完全避免网络重复请求
    • 静默恢复处理常见的连接问题

    本文就以请求使用为入口,来深入学习下OkHttp。

    一、请求流程分析

    1. 同步请求

    Okhttp同步GET请求使用:

    // 新建一个Okhttp客户端(也可以通过OkHttpClient.Builder来构造)
    OkHttpClient client = new OkHttpClient();
    // 构造一个请求对象
    Request request = new Request.Builder().url(url).build();
    // 执行同步请求,返回响应
    Response response = client.newCall(request).execute();
    // 从响应体中获取数据
    String str = response.body().string();
    

    先来瞧瞧构建OkhttpClient的源码:

    open class OkHttpClient internal constructor(
      builder: Builder
    ) : Cloneable, Call.Factory, WebSocket.Factory {
    	//若直接实例化OkHttpClient,则调用主构造函数以默认Builder作为参数
    	constructor() : this(Builder())
    
    	// 通过builder中的值赋值
    	@get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher
    
      	@get:JvmName("connectionPool") val connectionPool: ConnectionPool = builder.connectionPool
    	...
    	
    	class Builder constructor() {
    	    //分发器
    	    internal var dispatcher: Dispatcher = Dispatcher()
    	    //连接池
    	    internal var connectionPool: ConnectionPool = ConnectionPool()
    	    //应用拦截器集合
    	    internal val interceptors: MutableList<Interceptor> = mutableListOf()
    	    //网络拦截器集合
    	    internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
    	    //事件监听工厂
    	    internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
    	    //连接失败是否重试
    	    internal var retryOnConnectionFailure = true
    	    internal var authenticator: Authenticator = Authenticator.NONE
    	    //是否跟随重定向
    	    internal var followRedirects = true
    	    internal var followSslRedirects = true
    	    //cookie
    	    internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
    	    //磁盘缓存
    	    internal var cache: Cache? = null
    	    //dns
    	    internal var dns: Dns = Dns.SYSTEM
    	    //代理设置
    	    internal var proxy: Proxy? = null
    	    
    		...
        }
        
    }
    

    OkhttpClient可以通过构造者配置参数来构建,也可以直接实例化,直接实例化其实也是内部调用构造者,只是传入的是默认builder。

    再来看看OkhttpClient的newCall方法

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

    发现返回的是RealCall,接下来去RealCall中看后续的execute执行方法

    override fun execute(): Response {
      //确认call没有执行过并置executed为true,否则抛出异常
      check(executed.compareAndSet(false, true)) { "Already Executed" }
    
      timeout.enter()
      callStart()
      try {
        //标记执行中
        client.dispatcher.executed(this)
        //通过拦截器链获取网络响应
        return getResponseWithInterceptorChain()
      } finally {
        //标记执行结束
        client.dispatcher.finished(this)
      }
    }
    

    看起来比较精简,通过拦截器链获取网络响应,然后返回响应(拦截器链路在后续拦截器分析)。

    2. 异步请求

    Okhttp异步GET请求使用:

    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder().url(url).build();
    // 执行异步请求,通过回调返回响应
    client.newCall(request).enqueue(new Callback() {
          @Override
          public void onFailure(@NotNull Call call, @NotNull IOException e) {}
    
          @Override
          public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
          	// 从回调中通过响应体获取数据
          	String str = response.body().string();
          }
    });
    

    异步请求流程大致和同步请求相似,但是最后的执行方法是enqueue,并传入回调对象。

    我们来看看源码:

    override fun enqueue(responseCallback: Callback) {
      //确认call没有执行过并置executed为true,否则抛出异常
      check(executed.compareAndSet(false, true)) { "Already Executed" }
      //监听回调
      callStart()
      //调用Dispatcher的enqueue方法,并传入一个AsyncCall对象
      client.dispatcher.enqueue(AsyncCall(responseCallback))
    }
    

    内部调用了客户端的分发器的enqueue方法,并把AsyncCall(responseCallback)作为参数传入,AsyncCall是继承自Runnable,且是RealCall的内部类,我们先看Dispatcher.enqueue()方法

    class Dispatcher constructor() {
      /** '异步准备执行'队列 */
      private val readyAsyncCalls = ArrayDeque<AsyncCall>()
    
      /** '异步正在执行'队列,包括取消但至今还没结束的 */
      private val runningAsyncCalls = ArrayDeque<AsyncCall>()
    
      /** ‘同步正在执行’队列*/
      private val runningSyncCalls = ArrayDeque<RealCall>()
      ...
      internal fun enqueue(call: AsyncCall) {
    	synchronized(this) {
    	  //加入准备执行队列
    	  readyAsyncCalls.add(call)
    	  ...
    	}
    	// 执行
    	promoteAndExecute()
      }
    
      private fun promoteAndExecute(): Boolean {
        this.assertThreadDoesntHoldLock()
    
        val executableCalls = mutableListOf<AsyncCall>()
        val isRunning: Boolean
        synchronized(this) {
          val i = readyAsyncCalls.iterator()
          while (i.hasNext()) {
            val asyncCall = i.next()
            //检查请求是否超过最大请求数
            if (runningAsyncCalls.size >= this.maxRequests) break
            //检查请求是否超过一个Host对应的最大请求数
            if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue
    
            i.remove()
            asyncCall.callsPerHost.incrementAndGet()
            executableCalls.add(asyncCall)
            runningAsyncCalls.add(asyncCall)
          }
          isRunning = runningCallsCount() > 0
        }
    
        for (i in 0 until executableCalls.size) {
          val asyncCall = executableCalls[i]
          //调用AsyncCall的executeOn()方法
          asyncCall.executeOn(executorService)
        }
    
        return isRunning
      }
    }
    

    可以从上面代码看出,就是将符合条件的调用从readyAsyncCalls队列提升到runningAsyncCalls,并调用 AsyncCall的executeOn() 方法,把线程池传入。

    我们来看看AsyncCall:

      inner class AsyncCall(
        private val responseCallback: Callback
      ) : Runnable {
    	...
        fun executeOn(executorService: ExecutorService) {
          client.dispatcher.assertThreadDoesntHoldLock()
    
          var success = false
          try {
            //使用线程池执行自己的run()方法
            executorService.execute(this)
            success = true
          } catch (e: RejectedExecutionException) {
            ...
            //失败回调
            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 {
              //和同步请求一样,通过拦截器链获取网络响应
              val response = getResponseWithInterceptorChain()
              signalledCallback = true
              //回调成功
              responseCallback.onResponse(this@RealCall, response)
            } catch (e: IOException) {
              if (signalledCallback) {
                ...
              } else {
                //回调失败
                responseCallback.onFailure(this@RealCall, e)
              }
            } catch (t: Throwable) {
              cancel()
              if (!signalledCallback) {
                ...
                //回调失败
                responseCallback.onFailure(this@RealCall, canceledException)
              }
              throw t
            } finally {
              //标记结束
              client.dispatcher.finished(this)
            }
          }
        }
      }
    

    使用线程池来执行自己,接下来就看run()方法,发现和同步请求一样,通过拦截器链获取网络响应,再调用回调对象的回调方法返回响应。

    二、拦截器分析

    请求大致流程知道了,我们来看看重头戏,拦截器链里面做了什么操作。

    @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
      if (!forWebSocket) {
        // 用户设置的所有网络拦截器
        interceptors += client.networkInterceptors
      }
      // 服务器请求拦截器
      interceptors += CallServerInterceptor(forWebSocket)
    
      val chain = RealInterceptorChain(
          call = this,
          interceptors = interceptors,
          index = 0,
          exchange = null,
          request = originalRequest,
          connectTimeoutMillis = client.connectTimeoutMillis,
          readTimeoutMillis = client.readTimeoutMillis,
          writeTimeoutMillis = client.writeTimeoutMillis
      )
    
      var calledNoMoreExchanges = false
      try {
        //使用责任链模式开启链式调用
        val response = chain.proceed(originalRequest)
        if (isCanceled()) {
          response.closeQuietly()
          throw IOException("Canceled")
        }
        //返回响应
        return response
      } catch (e: IOException) {
        calledNoMoreExchanges = true
        throw noMoreExchanges(e) as Throwable
      } finally {
        if (!calledNoMoreExchanges) {
          noMoreExchanges(null)
        }
      }
    }
    

    我们在看下RealInterceptorChain的proceed方法:

      @Throws(IOException::class)
      override fun proceed(request: Request): Response {
    	...
        // 复制一个RealInterceptorChain,用于调用链中的下一个拦截器
        val next = copy(index = index + 1, request = request)
        val interceptor = interceptors[index]
    
        @Suppress("USELESS_ELVIS")
        // 调用下一个拦截器的intercept方法,获取response返回给上一个拦截器
        val response = interceptor.intercept(next) ?: throw NullPointerException(
            "interceptor $interceptor returned null")
    	...
        return response
      }
    
    

    接下来我们来具体看看各个拦截器的作用

    1. RetryAndFollowUpInterceptor

    RetryAndFollowUpInterceptor 处理错误恢复和重定向,它会判断错误是否满足条件进行重试,还有根据返回的响应判断是否需要重定向请求。

    class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Interceptor {
    
      @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) {
          // 初始化ExchangeFinder(后续ConnectInterceptor会用到ExchangeFinder来查找连接)
          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) {
              ...
              // 满足条件则重试
              continue
            } catch (e: IOException) {
              ...
              // 满足条件则重试
              continue
            }
    
            // 赋上重定向之前的响应(响应体置空)
            if (priorResponse != null) {
              response = response.newBuilder()
                  .priorResponse(priorResponse.newBuilder()
                      .body(null)
                      .build())
                  .build()
            }
    
            val exchange = call.interceptorScopedExchange
            //判断是否需重定向,若需则返回重定向请求
            val followUp = followUpRequest(response, exchange)
    
            //不需要重定向则直接返回response
            if (followUp == null) {
              if (exchange != null && exchange.isDuplex) {
                call.timeoutEarlyExit()
              }
              closeActiveExchange = false
              return response
            }
    
            val followUpBody = followUp.body
            // 若该请求只可传输一次,则返回响应
            if (followUpBody != null && followUpBody.isOneShot()) {
              closeActiveExchange = false
              return response
            }
    
            response.body?.closeQuietly()
    
            //超过重定向最大次数则抛出异常
            if (++followUpCount > MAX_FOLLOW_UPS) {
              throw ProtocolException("Too many follow-up requests: $followUpCount")
            }
    
            //将请求重新赋值为重定向的请求,继续循环,再次发送
            request = followUp
            priorResponse = response
          } finally {
            call.exitNetworkInterceptorExchange(closeActiveExchange)
          }
        }
      }
      ...
    }
    

    2. BridgeInterceptor

    BridgeInterceptor 桥接应用层和网络层的代码,对用户的请求进行加工(如对请求头进行设置添加),也对网络响应做相应的处理(如解压服务端返回的 gzip 压缩数据)。

    class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor {
    
      @Throws(IOException::class)
      override fun intercept(chain: Interceptor.Chain): Response {
        // 获取用户请求
        val userRequest = chain.request()
        // 真正发送的网络请求的构建者
        val requestBuilder = userRequest.newBuilder()
    
        // 用户请求的请求体
        val body = userRequest.body
        // 对请求头的设置
        ...
        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)
        }
    
        // 执行下一个拦截器,获取网络响应
        val networkResponse = chain.proceed(requestBuilder.build())
    
        cookieJar.receiveHeaders(userRequest.url, networkResponse.headers)
    
        val responseBuilder = networkResponse.newBuilder()
            .request(userRequest)
    
        // 若因配置问题,服务端返回gzip压缩的数据,则做相应的解压缩
        if (transparentGzip &&
            "gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) &&
            networkResponse.promisesBody()) {
          val responseBody = networkResponse.body
          if (responseBody != null) {
            // GzipSource对象,用于解压
            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()
      }
    }
    

    3. CacheInterceptor

    CacheInterceptor 承担着缓存的查找与保存的职责。根据策略判断是使用缓存还是走网络请求,对于返回的响应,满足条件则进行缓存。

    class CacheInterceptor(internal val cache: Cache?) : Interceptor {
    
      @Throws(IOException::class)
      override fun intercept(chain: Interceptor.Chain): Response {
        val call = chain.call()
        val cacheCandidate = cache?.get(chain.request())
    
        val now = System.currentTimeMillis()
    
        // 检查缓存策略
        val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()
        // 若还需发送网络请求,则networkRequest不为空
        val networkRequest = strategy.networkRequest
        // 若存在可用缓存,则cacheResponse不为空
        val cacheResponse = strategy.cacheResponse
    
        ...
    
        // 如果我们被禁止使用网络,并且无可用缓存,则返回失败
        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)
              }
        }
        
        // 如果不需要网络请求,缓存可用,则返回缓存
        if (networkRequest == null) {
          return cacheResponse!!.newBuilder()
              .cacheResponse(stripBody(cacheResponse))
              .build().also {
                listener.cacheHit(call, it)
              }
        }
    
        ...
    
        var networkResponse: Response? = null
        try {
          // 若无缓存可用,则执行下一个拦截器,获取响应
          networkResponse = chain.proceed(networkRequest)
        } finally {
          if (networkResponse == null && cacheCandidate != null) {
            cacheCandidate.body?.closeQuietly()
          }
        }
        
        // 如果我们还有缓存响应,且网络响应code为304,则更新缓存响应,并返回
        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()
    
            cache!!.trackConditionalCacheHit()
            // 更新缓存
            cache.update(cacheResponse, response)
            return response.also {
              listener.cacheHit(call, it)
            }
          } else {
            cacheResponse.body?.closeQuietly()
          }
        }
    
        // 包装网络响应
        val response = networkResponse!!.newBuilder()
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build()
    
        // 若用户配置了缓存
        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) {
              // cache无法被写
            }
          }
        }
    
        return response
      }
    }
    

    4. ConnectInterceptor

    ConnectInterceptor 主要是给网络请求提供一个连接,并交给下一个拦截器处理,这里还没有发送请求到服务器获取响应。在获取连接对象的时候,使用了连接池ConnectionPool来复用连接。

    object ConnectInterceptor : Interceptor {
      @Throws(IOException::class)
      override fun intercept(chain: Interceptor.Chain): Response {
        val realChain = chain as RealInterceptorChain
        // 查找新连接或池里的连接以承载即将到来的请求和响应
        val exchange = realChain.call.initExchange(chain)
        val connectedChain = realChain.copy(exchange = exchange)
        return connectedChain.proceed(realChain.request)
      }
    }
    

    ConnectInterceptor 看似代码很少,其实代码都在深处,看下initExchange方法

    internal fun initExchange(chain: RealInterceptorChain): Exchange {
      ...
      // codec(ExchangeCodec) 是一个连接所用的编码解码器,用于编码HTTP请求和解码HTTP响应
      val codec = exchangeFinder.find(client, chain)
      // result(Exchange)是封装这个编码解码器的一个工具类,用于管理ExchangeCodec,处理实际的 I/O
      val result = Exchange(this, eventListener, exchangeFinder, codec)
      ...
      return result
    }
    

    ExchangeCodec持有连接,可通过其编码请求到服务端和获取服务端的响应并解码,我们依方法进入到最深处,看看是连接是如何获取的(代码已做简化处理)。

    private fun findConnection(): RealConnection {
    
      // 1、复用当前连接
      val callConnection = call.connection 
      if (callConnection != null) {
          //检查这个连接是否可用和可复用
          if (callConnection.noNewExchanges || !sameHostAndPort(callConnection.route().address.url)) {
            toClose = call.releaseConnectionNoEvents()
          }
        return callConnection
      }
    
     //2、从连接池中获取可用连接
      if (connectionPool.callAcquirePooledConnection(address, call, null, false)) {
        val result = call.connection!!
        eventListener.connectionAcquired(call, result)
        return result
      }
    
      //3、从连接池中获取可用连接,通过一组路由routes(涉及知识点Http2多路复用)
      if (connectionPool.callAcquirePooledConnection(address, call, routes, false)) {
          val result = call.connection!!
          return result
        }
      route = localRouteSelection.next()
    
    
      // 4、创建新连接,进行tcp连接
      val newConnection = RealConnection(connectionPool, route)
      newConnection.connect
    
      // 5、再获取一次连接,在新建连接过程中可能有其他竞争连接被创建了,如可用防止浪费
      if (connectionPool.callAcquirePooledConnection(address, call, routes, true)) {
      	val result = call.connection!! 
      	// 关闭刚刚创建的新连接
      	newConnection.socket().closeQuietly()
        return result
      }
    
      //6、还是要使用创建的新连接,放入连接池,并返回
      connectionPool.put(newConnection)
      return newConnection
    }
    

    5. CallServerInterceptor

    CallServerInterceptor 是真正向服务器发起请求并获取响应的,它是拦责任链的最后一个拦截器,拿到响应后返回给上一个拦截器。代码已做简化(省略了很多条件判断和处理)。

    class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor {
    
      @Throws(IOException::class)
      override fun intercept(chain: Interceptor.Chain): Response {
        val realChain = chain as RealInterceptorChain
        // ConnectInterceptor获取到的,持有编码解码器
        val exchange = realChain.exchange!!
        val request = realChain.request
        val requestBody = request.body
        val sentRequestMillis = System.currentTimeMillis()
        
        var responseBuilder: Response.Builder? = null
        try {
          // 写入请求头
          exchange.writeRequestHeaders(request)
    
    	  if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
    	  	if (...) {
    	  		// 写入请求体
    	  		val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
                requestBody.writeTo(bufferedRequestBody)
                bufferedRequestBody.close()
    	  	} else {
    	  		...
    	  	}
    	  } else {
    	    // 无请求体
            exchange.noRequestBody()
          }
        } catch (e: IOException) {...}
    
        try {
          if (responseBuilder == null) {
            // 读取响应头
            responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
            if (invokeStartEvent) {
              exchange.responseHeadersStart()
              invokeStartEvent = false
            }
          }
          // 构建响应
          var response = responseBuilder
              .request(request)
              .handshake(exchange.connection.handshake())
              .sentRequestAtMillis(sentRequestMillis)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build()
          var code = response.code
          // 读取响应体
          response = if (forWebSocket && code == 101) {
            response.newBuilder()
                .body(EMPTY_RESPONSE)
                .build()
          } else {
            response.newBuilder()
                .body(exchange.openResponseBody(response))
                .build()
          }
          ...
          return response
        } catch (e: IOException) {
          ...
        }
      }
    }
    

    总结

    以上就是对OkHttp的源码解析,可以看出它是一个结构清晰的优质源码库,各个模块通过设计模式解耦。总结下流程:首先通过OkHttpClient对象调用newCall方法得到RealCall实例,再通过调用RealCall的execute方法或enqueue方法,这两个方法最终都会调用到getResponseWithInterceptorChain方法,运用责任链模式,开始一层层传入各个拦截器,每个拦截器都有着自己都职责,最终在CallServerInterceptor发出请求并获取响应,然后层层返回响应。

    参考文献

    OkHttp源码 v4.9.1
    《Android应用开发进阶》
    Andriod 网络框架 OkHttp 源码解析
    B站大厂面试真题解析视频合集

  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/chengsisi/p/14746420.html
Copyright © 2011-2022 走看看