简介

okhttp是Android中应用最广的http网络请求框架。结构优雅,性能强大。我们通过阅读它,对网络库的架构进行学习。本篇主要阅读okhttp的网络请求拦截链模型。

基本结构

okhttp采用拉截链的模型,将网络请求的各个部分,以一个个拦截器的方法,加入拦截链。
okhttp——网络请求模型 - 图1

详细代码

我们知道,在okhttp的任务调度模型中,最终任务,会调用execute方法。我们先来看execute方法。

  1. override fun execute() {
  2. var signalledCallback = false
  3. transmitter.timeoutEnter()
  4. try {
  5. val response = getResponseWithInterceptorChain()
  6. signalledCallback = true
  7. responseCallback.onResponse(this@RealCall, response)
  8. } catch (e: IOException) {
  9. if (signalledCallback) {
  10. // Do not signal the callback twice!
  11. Platform.get().log(INFO, "Callback failure for ${toLoggableString()}", e)
  12. } else {
  13. responseCallback.onFailure(this@RealCall, e)
  14. }
  15. } finally {
  16. client.dispatcher().finished(this)
  17. }
  18. }

这个方法中,实现网络请求的关键调用是:getResponseWithInterceptorChain。其他主要还是调用回调或处理异常。

拼装拦截链

  1. @Throws(IOException::class)
  2. fun getResponseWithInterceptorChain(): Response {
  3. // Build a full stack of interceptors.
  4. val interceptors = ArrayList<Interceptor>()
  5. interceptors.addAll(client.interceptors())
  6. interceptors.add(RetryAndFollowUpInterceptor(client))
  7. interceptors.add(BridgeInterceptor(client.cookieJar()))
  8. interceptors.add(CacheInterceptor(client.internalCache()))
  9. interceptors.add(ConnectInterceptor(client))
  10. if (!forWebSocket) {
  11. interceptors.addAll(client.networkInterceptors())
  12. }
  13. interceptors.add(CallServerInterceptor(forWebSocket))
  14. val chain = RealInterceptorChain(interceptors, transmitter, null, 0,
  15. originalRequest, this, client.connectTimeoutMillis(),
  16. client.readTimeoutMillis(), client.writeTimeoutMillis())
  17. var calledNoMoreExchanges = false
  18. try {
  19. val response = chain.proceed(originalRequest)
  20. if (transmitter.isCanceled) {
  21. closeQuietly(response)
  22. throw IOException("Canceled")
  23. }
  24. return response
  25. } catch (e: IOException) {
  26. calledNoMoreExchanges = true
  27. throw transmitter.noMoreExchanges(e) as Throwable
  28. } finally {
  29. if (!calledNoMoreExchanges) {
  30. transmitter.noMoreExchanges(null)
  31. }
  32. }
  33. }

这块儿代码基本还是简单清晰的。先用ArrayList<Interceptor>保存拦截器的队列,然后生成RealInterceptorChain,最后调用proceed方法,获取response。

我们先来看拦截器的抽象实现。

  1. /**
  2. * Observes, modifies, and potentially short-circuits requests going out and the corresponding
  3. * responses coming back in. Typically interceptors add, remove, or transform headers on the request
  4. * or response.
  5. */
  6. interface Interceptor {
  7. @Throws(IOException::class)
  8. fun intercept(chain: Chain): Response
  9. companion object {
  10. // This lambda conversion is for Kotlin callers expecting a Java SAM (single-abstract-method).
  11. @JvmName("-deprecated_Interceptor")
  12. inline operator fun invoke(
  13. crossinline block: (chain: Chain) -> Response
  14. ): Interceptor = object : Interceptor {
  15. override fun intercept(chain: Chain) = block(chain)
  16. }
  17. }
  18. interface Chain {
  19. fun request(): Request
  20. @Throws(IOException::class)
  21. fun proceed(request: Request): Response
  22. /**
  23. * Returns the connection the request will be executed on. This is only available in the chains
  24. * of network interceptors; for application interceptors this is always null.
  25. */
  26. fun connection(): Connection?
  27. fun call(): Call
  28. fun connectTimeoutMillis(): Int
  29. fun withConnectTimeout(timeout: Int, unit: TimeUnit): Chain
  30. fun readTimeoutMillis(): Int
  31. fun withReadTimeout(timeout: Int, unit: TimeUnit): Chain
  32. fun writeTimeoutMillis(): Int
  33. fun withWriteTimeout(timeout: Int, unit: TimeUnit): Chain
  34. }
  35. }

intercept方法,就是拦截器的核心,输入Chain,返回Response。

我们随意找一个Interceptor来进行阅读

RetryAndFollowUpInterceptor

  1. @Override public Response intercept(Chain chain) throws IOException {
  2. Request request = chain.request();
  3. RealInterceptorChain realChain = (RealInterceptorChain) chain;
  4. Transmitter transmitter = realChain.transmitter();
  5. int followUpCount = 0;
  6. Response priorResponse = null;
  7. while (true) {
  8. transmitter.prepareToConnect(request);
  9. if (transmitter.isCanceled()) {
  10. throw new IOException("Canceled");
  11. }
  12. Response response;
  13. boolean success = false;
  14. try {
  15. response = realChain.proceed(request, transmitter, null);
  16. success = true;
  17. } catch (RouteException e) {
  18. // The attempt to connect via a route failed. The request will not have been sent.
  19. if (!recover(e.getLastConnectException(), transmitter, false, request)) {
  20. throw e.getFirstConnectException();
  21. }
  22. continue;
  23. }
  24. ...
  25. }

这一段逻辑中,我们传入的是chain,即整个拦截链,会在中间调用realChain.proceed()。表示,在当前拦截器中,我们只做我们职责之类的逻辑,其余的逻辑,交给传入Chain的下一环

由此我们得知,RealInterceptorChain其实是一次请求所要做的所有工作。每一个Interceptor只负责一部分工作。它们的顺序是从外到内,当完成自己部分的外层功能后,就会将接下来的工作,交给下一层去完成。RetryAndFollowUpInterceptor只负责重试和重定向这些外层工作,其实逻辑会交由拦截器链的下一环节实现。Interceptor本身不用关心下一级的Interceptor是谁。

接下来,我们再看一下,RealInterceptorChain的逻辑。

RealInterceptorChain

RealInterceptorChain中有一个index的索引。它标识了当前拦截器链路进行到了哪一环。
我们着重看RealInterceptorChain的proceed方法,看一下Interceptor是如何前进到下一环的。

  1. class RealInterceptorChain(
  2. private val interceptors: List<Interceptor>,
  3. private val transmitter: Transmitter,
  4. private val exchange: Exchange?,
  5. private val index: Int,
  6. private val request: Request,
  7. private val call: Call,
  8. private val connectTimeout: Int,
  9. private val readTimeout: Int,
  10. private val writeTimeout: Int
  11. ) : Interceptor.Chain {
  12. private var calls: Int = 0
  13. ......
  14. override fun proceed(request: Request): Response {
  15. return proceed(request, transmitter, exchange)
  16. }
  17. @Throws(IOException::class)
  18. fun proceed(request: Request, transmitter: Transmitter, exchange: Exchange?): Response {
  19. if (index >= interceptors.size) throw AssertionError()
  20. calls++
  21. // If we already have a stream, confirm that the incoming request will use it.
  22. if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
  23. throw IllegalStateException("network interceptor " + interceptors[index - 1] +
  24. " must retain the same host and port")
  25. }
  26. // If we already have a stream, confirm that this is the only call to chain.proceed().
  27. if (this.exchange != null && calls > 1) {
  28. throw IllegalStateException("network interceptor " + interceptors[index - 1] +
  29. " must call proceed() exactly once")
  30. }
  31. // Call the next interceptor in the chain.
  32. val next = RealInterceptorChain(interceptors, transmitter, exchange,
  33. index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
  34. val interceptor = interceptors[index]
  35. @Suppress("USELESS_ELVIS")
  36. val response = interceptor.intercept(next) ?: throw NullPointerException(
  37. "interceptor $interceptor returned null")
  38. // Confirm that the next interceptor made its required call to chain.proceed().
  39. if (exchange != null && index + 1 < interceptors.size && next.calls != 1) {
  40. throw IllegalStateException("network interceptor " + interceptor +
  41. " must call proceed() exactly once")
  42. }
  43. if (response.body() == null) {
  44. throw IllegalStateException(
  45. "interceptor $interceptor returned a response with no body")
  46. }
  47. return response
  48. }
  49. }

这一段代码首先对index进行了检查,然后对call,exchange中的种种参数进行了检查。最后调用了

  1. // Call the next interceptor in the chain.
  2. val next = RealInterceptorChain(interceptors, transmitter, exchange,
  3. index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
  4. val interceptor = interceptors[index]
  5. @Suppress("USELESS_ELVIS")
  6. val response = interceptor.intercept(next) ?: throw NullPointerException(
  7. "interceptor $interceptor returned null")

调用当前interceptor的intercept方法,并将下一个interceptor传入。

小结

okhttp的网络请求,采用了interceptor这样的结构,因为网络请求是一个层级深,分支少的结构。每一个层级并不关心下一个层级的实现。因此,这样的结构很合适。

发散一下,对于层级深,分支少,交付结果一致的业务模型,我们也可以采用这种interceptor的模型。方便层级之前解耦合。

如有问题,欢迎指正。