OkHttp源码分析——CallServerInterceptor拦截器

CallServerInterceptor拦截器是Okhttp框架内置拦截器的最后一个,在上一个拦截器ConnectInterceptor中客户端已经和服务器建立的连接,**CallServerInterceptor拦截器主要负责将请求发送给服务器,并从服务器获取响应。**它的拦截方法如下:
简述方法:首先会把不包含请求体的请求发送给客户端,如果有请求体还需要询问服务器是否愿意接收,服务器愿意接收再把请求体发过去,请求发送完成。从服务器获取响应返回。

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

    long sentRequestMillis = System.currentTimeMillis();

    realChain.eventListener().requestHeadersStart(realChain.call());
    //将request发送给服务器,此时只发送了请求行和请求头
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    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(用来询问服务器是否愿意接收请求体)
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
      //刷新请求
        httpCodec.flushRequest();
        realChain.eventListener().responseHeadersStart(realChain.call());
        //返回服务器的响应。responseBuilder =null则代表服务器愿意接收请求体,否则不愿意。
        responseBuilder = httpCodec.readResponseHeaders(true);
      }
      // 服务器愿意接收请求体
      if (responseBuilder == null) {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        realChain.eventListener().requestBodyStart(realChain.call());
        //下面这些代码用来将请求体发送给服务器。
        long contentLength = request.body().contentLength();
        CountingSink requestBodyOut =
            new CountingSink(httpCodec.createRequestBody(request, contentLength));
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);

        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
        realChain.eventListener()
            .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
      } else if (!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.
        streamAllocation.noNewStreams();
      }
    }
    //结束请求
    httpCodec.finishRequest();
    //responseBuilder == null代表发送的请求没有请求体比如get请求或服务器愿意接收请求体
    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      //从服务器返回的数据构建responseBuilder 对象
      responseBuilder = httpCodec.readResponseHeaders(false);
    }
     //构建response对象。暂时还没包含响应头
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();
    if (code == 100) {
      // server sent a 100-continue even though we did not request one.
      // try again to read the actual response
      responseBuilder = httpCodec.readResponseHeaders(false);

      response = responseBuilder
              .request(request)
              .handshake(streamAllocation.connection().handshake())
              .sentRequestAtMillis(sentRequestMillis)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();

      code = response.code();
    }

    realChain.eventListener()
            .responseHeadersEnd(realChain.call(), response);

    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 {
    //响应体
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }

    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;
  }

方法整体流程分析完了再来看一些细节问题:
HttpMethod.permitsRequestBody()方法:如果这个请求不是Get或者HEAD请求就返回true,否则返回false。如果是get请求也没必要询问服务器是否愿意接收请求体。

f (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
    //请求不是Get或者HEAD请求并且有请求体。
      }
      
 public static boolean permitsRequestBody(String method) {
    return !(method.equals("GET") || method.equals("HEAD"));
  }

请求头通过携带特殊字段Expect: 100-continue来询问服务器是否愿意接收请求体。

if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        //如果服务器愿意接收请求体就会返回null
        responseBuilder = httpCodec.readResponseHeaders(true);
      }

readResponseHeaders(true)方法,注意参数为true。

@Override public Response.Builder readResponseHeaders(boolean expectContinue) throws IOException {
      //...
      StatusLine statusLine = StatusLine.parse(readHeaderLine());

      Response.Builder responseBuilder = new Response.Builder()
          .protocol(statusLine.protocol)
          .code(statusLine.code)
          .message(statusLine.message)
          .headers(readHeaders());

      if (expectContinue && statusLine.code == HTTP_CONTINUE) {
        return null;
      } 
      //...
      return responseBuilder;
    } 
  }

可以看到如果服务器返回的响应代码为HTTP_CONTINUE(100),就直接返回空。在客户端询问服务器自己是否可以发送请求体之后,服务器通过发送携带100状态码的响应表示自己愿意接收。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值