【Android】OkHttp系列(六):CallServerInterceptor

该系列OkHttp源码分析基于OkHttp3.14.0版本

概述

用于向服务器写数据以及从服务器读取数据。

整个拦截器的主要逻辑是这样的,首先向服务器发送请求头,如果有请求体的话就向服务器发送请求体,然后就开始读取服务器的返回。同样的,首先读取服务器返回的响应头,然后根据状态码以及是否是websocket协议判断是继续读取响应头还是开始读取响应体。最后按照责任链,向上返回响应。

而且根据源码可以看到,所有与服务器的读写操作都是由Exchange进行的,而根据上面连接拦截器ConnectInterceptor所提及的,Exchange中实际与服务器进行IO交互的是ExchangeCodec,而ExchangeCodec中封装了Okio的IO操作。

源码分析

发送请求

@Override public Response intercept(Chain chain) throws IOException {
  RealInterceptorChain realChain = (RealInterceptorChain) chain;
  Exchange exchange = realChain.exchange();
  Request request = realChain.request();

  long sentRequestMillis = System.currentTimeMillis();

  exchange.writeRequestHeaders(request);//发送请求头

  boolean responseHeadersStarted = false;
  Response.Builder responseBuilder = null;
  //判断是否有请求体
  if (HttpMethod.permitsRequestBody(request.method()) && request.body() != 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.

    // 如果请求上有一个“Expect: 100-continue”标头,则在发送请求正文之前,等待“ HTTP / 1.1 100继续”响应。
    // 如果没有得到,请返回我们得到的结果(例如4xx响应),而无需传输请求主体。
    if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
      exchange.flushRequest();
      responseHeadersStarted = true;
      exchange.responseHeadersStart();
      responseBuilder = exchange.readResponseHeaders(true);
    }

    if (responseBuilder == null) {//这里判断的是是否有请求头返回
      // 下面开始发送请求体
      if (request.body().isDuplex()) {
        // Prepare a duplex body so that the application can send a request body later.

        // 准备一个双工主体,以便应用程序以后可以发送请求主体。
        exchange.flushRequest();
        BufferedSink bufferedRequestBody = Okio.buffer(
            exchange.createRequestBody(request, true));
        request.body().writeTo(bufferedRequestBody);
      } else {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        // 如果满足“Expect: 100-continue”的期望,写请求体。
        BufferedSink bufferedRequestBody = Okio.buffer(
            exchange.createRequestBody(request, false));
        request.body().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.
        // 如果未达到“Expect: 100-continue”的期望,请防止HTTP / 1连接被重用。
        // 否则,我们仍然有义务传输请求主体,以使连接保持一致状态。
        exchange.noNewExchangesOnConnection();
      }
    }
  } else {
    exchange.noRequestBody();
  }

  if (request.body() == null || !request.body().isDuplex()) {
    exchange.finishRequest();
  }

  ...省略部分代码
}

整个代码逻辑就如之前所说的,首先调用exchange.writeRequestHeaders()发送请求头,然后调用request.body().writeTo(bufferedRequestBody)发送请求体。这里有点特殊,发送请求体并不是由ExchangeCodec进行的,而是由BufferedSink进行的。至于为啥要这么做,emm,我也很好奇。

读取响应

@Override public Response intercept(Chain chain) throws IOException {
  RealInterceptorChain realChain = (RealInterceptorChain) chain;
  Exchange exchange = realChain.exchange();
  Request request = realChain.request();

  long sentRequestMillis = System.currentTimeMillis();

  exchange.writeRequestHeaders(request);//发送请求头

  boolean responseHeadersStarted = false;
  Response.Builder responseBuilder = null;
  
    ...省略部分代码

  if (!responseHeadersStarted) {
    exchange.responseHeadersStart();
  }

  if (responseBuilder == null) {
    //获得返回头
    responseBuilder = exchange.readResponseHeaders(false);
  }

  //构建响应返回
  Response response = responseBuilder
      .request(request)
      .handshake(exchange.connection().handshake())
      .sentRequestAtMillis(sentRequestMillis)
      .receivedResponseAtMillis(System.currentTimeMillis())
      .build();

  int code = response.code();
  if (code == 100) {//100表示需要继续想服务端发送数据
    // server sent a 100-continue even though we did not request one.
    // try again to read the actual response

    // 即使我们没有请求,服务器仍发送了100-continue。 再次尝试读取返回
    response = exchange.readResponseHeaders(false)
        .request(request)
        .handshake(exchange.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    code = response.code();
  }

  exchange.responseHeadersEnd(response);

  if (forWebSocket && code == 101) {//判断是否是websocket或者服务端返回要求切换协议
    // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
    // 连接正在升级,但是我们需要确保拦截器看到一个非空的响应主体。
    response = response.newBuilder()
        .body(Util.EMPTY_RESPONSE)
        .build();
  } else {
    response = response.newBuilder()
        .body(exchange.openResponseBody(response))//这里去拿到返回体
        .build();
  }

  if ("close".equalsIgnoreCase(response.request().header("Connection"))
      || "close".equalsIgnoreCase(response.header("Connection"))) {
    exchange.noNewExchangesOnConnection();//结束请求
  }

  if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
    //这里应该属于服务端的错误,204和205表示没有返回体,但是这里却发现有返回体
    throw new ProtocolException(
        "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
  }

  return response;
}
发布了24 篇原创文章 · 获赞 7 · 访问量 8680

猜你喜欢

转载自blog.csdn.net/d745282469/article/details/104297086
今日推荐