OkHttp - Interceptors(四)

本文中源码基于OkHttp 3.6.0

这篇文章分析 OkHttp 请求流程中的最后一个 Interceptor 节点 - CallServerInterceptor,它的任务就是向服务器发起最终的请求,完成写入请求,读取响应的工作。

- CallServerInterceptor

来看请求执行的入口 intercept 函数。

public Response intercept(Chain chain) throws IOException {
  HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
  StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
  Request request = chain.request();

  long sentRequestMillis = System.currentTimeMillis();
  // 写入请求 Header
  httpCodec.writeRequestHeaders(request);

  Response.Builder responseBuilder = null;
  // 如果请求允许携带 Body,写入 Body
  if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
    // 如果请求 Header 中包含了 "Expect: 100-continue”,其表示客户端希望服务器告知自己是否允许携带 Body,
    // 如果服务器返回状态码为100,则表示允许携带请求体,那么 readResponseHeaders 返回 null。
    if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
    // 刷新缓冲区,执行请求
      httpCodec.flushRequest();
      responseBuilder = httpCodec.readResponseHeaders(true);
    }

    // 写入请求 Body
    if (responseBuilder == null) {
      Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
      BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
      request.body().writeTo(bufferedRequestBody);
      bufferedRequestBody.close();
    }
  }

  // 刷新缓冲区,执行请求
  httpCodec.finishRequest();

  // 读取响应 Header,
  if (responseBuilder == null) {
    responseBuilder = httpCodec.readResponseHeaders(false);
  }

  // 创建响应
  Response response = responseBuilder
      .request(request)
      .handshake(streamAllocation.connection().handshake())
      .sentRequestAtMillis(sentRequestMillis)
      .receivedResponseAtMillis(System.currentTimeMillis())
      .build();

  int code = response.code();
  if (forWebSocket && code == 101) {
    // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
    response = response.newBuilder()
        .body(Util.EMPTY_RESPONSE)
        .build();
  } else {
    // 写入响应 Body
    response = response.newBuilder()
        .body(httpCodec.openResponseBody(response))
        .build();
  }

  // 如果 Header 中设置了 “Connection:close”,关闭连接
  if ("close".equalsIgnoreCase(response.request().header("Connection"))
      || "close".equalsIgnoreCase(response.header("Connection"))) {
    streamAllocation.noNewStreams();
  }

  if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
    throw new ProtocolException(
        "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
  }

  return response;
}

CallServerInterceptor执行请求过程主要分为4步,利用在上一个节点中创建的HttpCodec实现与服务器的交互:

  1. 写入 Request Header;
  2. 写入 Request Body;
  3. 读取 Response Header;
  4. 读取 Response Body。

至此, Request 请求过程中上游部分就结束了,一个原始的 Response 就被创建出来了,这个 Response 将按请求链上的反向路径一步步返回到上一个 Interceptor 节点,供其继续处理从服务器返回的 Response,直到最后返回给用户,完成一次网络请求。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 这篇文章主要讲 Android 网络请求时所使用到的各个请求库的关系,以及 OkHttp3 的介绍。(如理解有误,...
    小庄bb阅读 1,252评论 0 4
  • OkHttp解析系列 OkHttp解析(一)从用法看清原理OkHttp解析(二)网络连接OkHttp解析(三)关于...
    Hohohong阅读 21,059评论 4 58
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,292评论 19 139
  • 简介 目前在HTTP协议请求库中,OKHttp应当是非常火的,使用也非常的简单。网上有很多文章写了关于OkHttp...
    第八区阅读 1,410评论 1 5
  • 昨天停水,晚上的菜才做了一半。突然之间停水,毫无思想准备,顿时心里多出许多埋怨,还好,家里有预备的矿泉水,对付着把...
    卿若安阅读 207评论 0 1