CallServerInterceptor 解析

okhttp中 最后的拦截在这个责任链中,发送一个请求到服务器。先看下拦截

 @Override public Response intercept(Chain chain) throws IOException {
    //获得httpcodec
    HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
    //获得StreamAllocation
    StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
    //获取请求
    Request request = chain.request();

    //当前时间
    long sentRequestMillis = System.currentTimeMillis();
    httpCodec.writeRequestHeaders(request);

    Response.Builder responseBuilder = null;

    // public static boolean requiresRequestBody(String method) {
    //    return method.equals("POST")
    //        || method.equals("PUT")
    //        || method.equals("PATCH")
    //        || method.equals("PROPPATCH") // WebDAV
    //        || method.equals("REPORT");   // CalDAV/CardDAV (defined in WebDAV Versioning)
    //  }
    //
    //  public static boolean permitsRequestBody(String method) {
    //    return requiresRequestBody(method)
    //        || method.equals("OPTIONS")
    //        || method.equals("DELETE")    // Permitted as spec is ambiguous.
    //        || method.equals("PROPFIND")  // (WebDAV) without body: request 
    //        || method.equals("MKCOL")     // (WebDAV) may contain a body, but behaviour is unspecified
    //        || method.equals("LOCK");     // (WebDAV) body: create lock, without body: refresh lock
    //  }
    // 需要请求requestbody的请求方法,get请求没有requestbody
    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.

      //"100-continue" https://www.cnblogs.com/jikexianfeng/p/6100649.html
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        responseBuilder = httpCodec.readResponseHeaders(true);
      }

      // Write the request body, unless an "Expect: 100-continue" expectation failed.
      //在requet中写入 bufferedRequestBody
      if (responseBuilder == null) {
        Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
      }
    }

    //刷新请求,
    httpCodec.finishRequest();
    //根据服务器的返回构建一个 responsebuild对象
    if (responseBuilder == null) {
      responseBuilder = httpCodec.readResponseHeaders(false);
    }
    //构建response
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();
    //客户要求服务器根据请求转换HTTP协议版本
    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();
    }
  //close 表示操作完成后需要关闭当前连接 参考https://imququ.com/post/the-proxy-connection-header-in-http-request.html
    if ("close".equalsIgnoreCase(response.request().header("Connection"))
        || "close".equalsIgnoreCase(response.header("Connection"))) {
      streamAllocation.noNewStreams();
    }

    //204  请求收到,但返回信息为空  205 服务器完成了请求,用户代理必须复位当前已经浏览过的文件
    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
      throw new ProtocolException(
          "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
    }
    return response;
  }
  • 首先是将请求request写入到解析器中
  • 刷新请求
  • 构建返回response对象
    看下具体的过程,首先是得道责任链中传递的httpcodec,StreamAllocation,request,然后向sink流中写入header ,发送到服务器。其中这个sink就是连接的socket的写入流,在RealConnect中生成。
 @Override public void writeRequestHeaders(Request request) throws IOException {
    String requestLine = RequestLine.get(
        request, streamAllocation.connection().route().proxy().type());
    writeRequest(request.headers(), requestLine);
  }
  /** Returns bytes of a request header for sending on an HTTP transport.
   * 根据request发送http请求返回字节
   * */
  public void writeRequest(Headers headers, String requestLine) throws IOException {
    if (state != STATE_IDLE) throw new IllegalStateException("state: " + state);
    sink.writeUtf8(requestLine).writeUtf8("\r\n");
    for (int i = 0, size = headers.size(); i < size; i++) {
      sink.writeUtf8(headers.name(i))
          .writeUtf8(": ")
          .writeUtf8(headers.value(i))
          .writeUtf8("\r\n");
    }
    sink.writeUtf8("\r\n");
    state = STATE_OPEN_REQUEST_BODY;
  }

如果请求方式是非get请求,并且存在请求的body,直接将request写入到sink中,刷新socket,返回一个responsebuild对象。最后就是资源的释放了。

你可能感兴趣的:(CallServerInterceptor 解析)