okHttp框架分析--拦截链

概要

我把拦截器作为作为OkHttp框架的首篇是因为我认为它是OkHttp框架的精髓所在,无论我们的任何请求方式,最终都要经过一个个的拦截器,实现对网络的访问,它使用的是责任链模式,作用是在访问网络之前做一些 预前工作。

拦截链的组成

[ 1 ] 用户自定义拦截器​ - cient.interceptors()
[ 2 ] 重试并跟踪拦截器​ - RetryAndFollowUpInterceptor(client)
[ 3 ] 桥接拦截器​ - BridgeInterceptor(client.cookieJar())
[ 4 ] 缓存拦截器​ - CacheInterceptor(client.internalCache())
[ 5 ] 连接拦截器​ - ConnectInterceptor(client)
[ 6 ] 用户自定义网络拦截器​ - client.networkInterceptors()
[ 7 ] 服务器调用拦截器​ - CallServerInterceptor(forWebSocket)

其中 用户自定义拦截器 和 用户自定义网络拦截器 是用户自定义的,可以根据处理的业务自定义拦截器的功能。

源码剖析

okHttp框架分析--拦截链_第1张图片
拦截器链流程.jpg

外部调用入口

public class GetExample {
   //声明一个OkHttpClient对象
  OkHttpClient client = new OkHttpClient();

  String run(String url) throws IOException {
    //声明Request请求
    Request request = new Request.Builder()
        .url(url)
        .build();
    // [ 1 ] 调用execute()方法,进行网络请求,以此方法为入口调取拦截链
    try (Response response = client.newCall(request).execute()) {
      return response.body().string();
    }
  }

  public static void main(String[] args) throws IOException {
    GetExample example = new GetExample();
    String response = example.run("https://raw.github.com/square/okhttp/master/README.md");
    System.out.println(response);
  }
}

[1] client.newCall(request)方法声明了一个RealCall对象,而方法execute()进入了RealCall类中execute()实现方法后,进而调取方法getResponseWithInterceptorChain()

fun getResponseWithInterceptorChain(): Response {
  //添加完整的 拦截器链
  val interceptors = ArrayList()
  //添加 [用户自定义] 拦截器​
  interceptors.addAll(cient.interceptors())  
 //添加重试并跟踪拦截器​
  interceptors.add(RetryAndFollowUpInterceptor(client))
  //添加桥接拦截器​
  interceptors.add(BridgeInterceptor(client.cookieJar()))
 //添加缓存拦截器​
  interceptors.add(CacheInterceptor(client.internalCache()))
  //添加连接拦截器​
  interceptors.add(ConnectInterceptor(client))
  if (!forWebSocket) ​{
    //添加 [用户自定义] 网络拦截器​
    interceptors.addAll(client.networkInterceptors())
  }
  //添加最后一个服务器调用拦截器​
  interceptors.add(CallServerInterceptor(forWebSocket))
 //获取从拦截器链中 获取 第0个位置的拦截器包装成 RealInterceptorChain类型
  val chain = RealInterceptorChain(interceptors, transmitter, null, 0,
      originalRequest, this, client.connectTimeoutMillis(),
      client.readTimeoutMillis(), client.writeTimeoutMillis())
  var calledNoMoreExchanges = false
  try {
   //[ 2 ]​调取开始执行的方法
    val response = chain.proceed(originalRequest)
    if (transmitter.isCanceled) {
      closeQuietly(response)
      throw IOException("Canceled")
    }
    return response
  } catch (e: IOException) {
    calledNoMoreExchanges = true
    throw transmitter.noMoreExchanges(e) as Throwable
  } finally {
    if (!calledNoMoreExchanges) {
      transmitter.noMoreExchanges(null)
    }
  }
}

[ 2 ] 组织添加完所有的拦截器后,获取拦截链中第一个拦截器,调用chain.proceed(originalRequest)`方法,进行执行

fun proceed(request: Request, transmitter: Transmitter, exchange: Exchange?): Response {
  //判定当前 index是否 大于  ​拦截链的总数
  if (index >= interceptors.size) throw AssertionError()
  calls++  //调取次数
​  //如果我们已经有一个流,请确认传入的请求将使用它
  if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
    throw IllegalStateException("network interceptor " + interceptors[index - 1] +
        " must retain the same host and port")
  }
  //如果我们已经有了一个流,请确认这是对chain.proceed()的唯一调用
  if (this.exchange != null && calls > 1) {
    throw IllegalStateException("network interceptor " + interceptors[index - 1] +
        " must call proceed() exactly once")
  }
  // 获取链中的下一个拦截器的实例,封装成 RealInterceptorChain
  val next = RealInterceptorChain(interceptors, transmitter, exchange,
      index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
//获取当前的拦截器​
  val interceptor = interceptors[index] 
  @Suppress("USELESS_ELVIS")
  // [3] 执行当前拦截器的 intercept函数,并将下一个拦截器实例作为参数传入​
  val response = interceptor.intercept(next) ?: throw NullPointerException(
      "interceptor $interceptor returned null")
  //确认下一个拦截器调用了chain.proceed()
  if (exchange != null && index + 1 < interceptors.size && next.calls != 1) {
    throw IllegalStateException("network interceptor " + interceptor +
        " must call proceed() exactly once")
  }
  if (response.body() == null) {
    throw IllegalStateException(
        "interceptor $interceptor returned a response with no body")
  }
  //返回最终的Response实例​
  return response
}

[ 3 ] 执行当前拦截器的 intercept函数,并将下一个拦截器实例作为参数传入​方法interceptor.intercept(next)

提示

拦截链中的一个拦截器是 用户自定义的,若用户不进行第一,则第二拦截器将处于第一位置,即RetryAndFollowUpInterceptor拦截器,我们假设用户未进行自定义,则当前将进入RetryAndFollowUpInterceptor.kt,执行方法interceptor.intercept(next)

public final class RetryAndFollowUpInterceptor implements Interceptor {
  private static final int MAX_FOLLOW_UPS = 20;
  private final OkHttpClient client;
  public RetryAndFollowUpInterceptor(OkHttpClient client) {
    this.client = client;
  }
  @Override public Response intercept(Chain chain) throws IOException {
    //获取下一个拦截器中的 请求
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    //获取下一个拦截器的发射器​
    Transmitter transmitter = realChain.transmitter();
    int followUpCount = 0;
    Response priorResponse = null;
    while (true) {
     //准备创建一个携带{@code request}的流。如果存在连接,这更喜欢使用现有的 。
      transmitter.prepareToConnect(request);
      if (transmitter.isCanceled()) {
        throw new IOException("Canceled");
      }
      Response response;
      boolean success = false;
      try {
        //下一个拦截器调取proceed函数,进行执行​ 
        //​@重要 每一个拦截在完成自己所需处理的业务后,都回调取 @方法[ realChain.proceed(request, transmitter, null);]
        //然后在外部会传入 拦截链中的下一个拦截器实例,从而实现责任链模式,完成每一个链既定​业务,最后返回数据会逐次 [向上返]
        response = realChain.proceed(request, transmitter, null);
        success = true;
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        if (!recover(e.getLastConnectException(), transmitter, false, request)) {
          throw e.getFirstConnectException();
        }
        continue;
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
        if (!recover(e, transmitter, requestSendStarted, request)) throw e;
        continue;
      } finally {
        // 抛出一个网络调用异常,释放所有资源.
        if (!success) {
          transmitter.exchangeDoneDueToException();
        }
      }
      //以下处理皆要等待所有的拦截器执行完毕,逐次[向上]返
      ...
      priorResponse = response;
    }
  }

[4] 下一个拦截器调取proceed函数,进行执行​;每个[拦截器]完成既定的业务都会调取下一个拦截器,最后调取CallServerInterceptor.kt的方法interceptor.intercept(next)

@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
  val realChain = chain as RealInterceptorChain
  val exchange = realChain.exchange()
  //获取请求实例​
  val request = realChain.request()    
 //获取请求体​
  val requestBody = request.body()
  ...
​  //@重点 做判定,若当前请求方法不是 GET或 HEAD 并且 请求体不为 Null 则判定成立
  if (HttpMethod.permitsRequestBody(request.method()) && requestBody != null) {
    //如果请求上有一个“Expect: 100-continue”报头,则等待一个“HTTP/1.1 100”报头 
  //在发送请求体之前继续“响应”。如果我们没有收到,返回
​  //在没有传输请求体的情况下,我们确实得到了(例如4xx响应)
​
  //在[预用知识说明]标签  ==>  { “Expect: 100-continue”的来龙去脉 }  中做详细说明​
    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()) {
        // 准备一个双重主体,以便应用程序稍后可以发送请求主体。
        exchange.flushRequest()
        //创建一个buffer​
        val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
         //请求体写入buff中​
        requestBody.writeTo(bufferedRequestBody)
      } else {
        // 如果满足“Expect: 100-continue”期望,则编写请求主体
        val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
        requestBody.writeTo(bufferedRequestBody)
        bufferedRequestBody.close()
      }
    } else {
      exchange.noRequestBody()
      if (!exchange.connection().isMultiplexed) {
        //如果没有满足“Expect: 100-continue”期望,请阻止HTTP/1连接
      ​ //避免重复使用。否则,我们仍然有义务将请求体传输到 
       //让连接保持一致的状态。
        exchange.noNewExchangesOnConnection()
      }
    }
  } else {
     //没有请求体​
    exchange.noRequestBody()
  }
​​
​
  if (requestBody == null || !requestBody.isDuplex()) {
    //将所有缓冲数据写入底层接收器(如果存在的话)。然后这个sink是递归不断刷新
   //​将数据尽可能地推送到最终目的地。通常, 目标是一个网络套接字或文件。​
    exchange.finishRequest()
  }
  if (!responseHeadersStarted) {
    //仅在接收响应头之前调用。 
  //​ 连接是隐式的,通常与最后一个[connectionAcquired]事件相关。 
  //​这可以被调用超过1次为一个[Call]。​
    exchange.responseHeadersStart()
  }
  if (responseBuilder == null) {
    //从HTTP传输解析响应头的字节。​
    responseBuilder = exchange.readResponseHeaders(false)!!
  }
  //一个HTTP响应。
 //​该类的实例不是不可变的:响应体是一次性的
 //​只使用一次,然后关闭的值。所有其他属性都是不可变的。​
  var response = responseBuilder
      .request(request)
      .handshake(exchange.connection().handshake())
      .sentRequestAtMillis(sentRequestMillis)
      .receivedResponseAtMillis(System.currentTimeMillis())
      .build()
  var code = response.code()  //获取响应 Code
  if (code == 100) {
    // 服务器发送了100-continue,即使我们没有请求。
   ​ //再读一遍实际的响应
    response = exchange.readResponseHeaders(false)!!
        .request(request)
        .handshake(exchange.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build()
    code = response.code()
  }
   //在接收响应标头后立即调用​
  exchange.responseHeadersEnd(response)
  response = if (forWebSocket && code == 101) {
    //连接叠积,但我们需要确保拦截器看到非空响应体。
    response.newBuilder()
        .body(Util.EMPTY_RESPONSE)
        .build()
  } else {
    response.newBuilder()
        .body(exchange.openResponseBody(response))
        .build()
  }
 //关闭连接​
  if ("close".equals(response.request().header("Connection"), ignoreCase = true) ||
      "close".equals(response.header("Connection"), ignoreCase = true)) {
    exchange.noNewExchangesOnConnection()
  }
 //抛出连接异常​
  if ((code == 204 || code == 205) && response.body()?.contentLength() ?: -1 > 0) {
    throw ProtocolException(
        "HTTP $code had non-zero Content-Length: ${response.body()?.contentLength()}")
  }
  //返回响应数据​
  return response
}

重要

每一个拦截在完成自己所需处理的业务后,都回调取方法realChain.proceed(request, transmitter, null);
然后在外部会传入 拦截链中的下一个拦截器实例,从而实现责任链模式,完成每一个链既定​业务,进入下一个链的调用,最后会在CallServerInterceptor.kt的方法interceptor.intercept(next)向服务器请求数据,最后返回数据会逐次 向上返,然后进行下半部分的业务处理,最后将获取的Response对象返回至前台

This ALL! Thanks EveryBody!

你可能感兴趣的:(okHttp框架分析--拦截链)