Okhttp再分析<二>

再分析第二篇准备讲讲CallServerInterceptor。先OkHttp的RealConnection 说起,它主要是创建链接,创建链接分为两部分。分为createTunnel(这不是直接连接服务器,是链接的代理服务器)和connectSocket 通过socket直接连接,(socket 是实现http协议的api),主要分析createSocket吧。

 /** Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */
  private void connectSocket(int connectTimeout, int readTimeout, Call call,
      EventListener eventListener) throws IOException {
    //proxy 的type分为直接连接,socket代理,http代理(一般Https,Ftp这种协议直接)  
    Proxy proxy = route.proxy();
    //获取地址。Address 属于服务器的抽象定义,如果直连,这注意hostname和port。如果是代理还包含代理信息,SocketFactory,证书等。
    Address address = route.address();
    //如果是直连或者http代理,那么直接获取到socket,否则传进去new Socket,socketFactory() 获取的是
    //DefaultSocketFactory 工厂。
    rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
        ? address.socketFactory().createSocket()
        : new Socket(proxy);

    eventListener.connectStart(call, route.socketAddress(), proxy);
    rawSocket.setSoTimeout(readTimeout);
    try {
    // 正式连接到socket。
      Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
    } catch (ConnectException e) {
      ConnectException ce = new ConnectException("Failed to connect to " + route.socketAddress());
      ce.initCause(e);
      throw ce;
    }

    // The following try/catch block is a pseudo hacky way to get around a crash on Android 7.0
    // More details:
    // https://github.com/square/okhttp/issues/3245
    // https://android-review.googlesource.com/#/c/271775/
    try {
    // Okio 粉墨登出,一句话它是链接socket,然后从中读取byte,转换为buffer。source输入输入流,sink是读取流,source 我们用于写入header和requestBody信息。sink我们用于读取RequestBody的信息。
      source = Okio.buffer(Okio.source(rawSocket));
      sink = Okio.buffer(Okio.sink(rawSocket));
    } catch (NullPointerException npe) {
      if (NPE_THROW_WITH_NULL.equals(npe.getMessage())) {
        throw new IOException(npe);
      }
    }
  }

这里我们看到了非常重要的角色souce和sink。现在回到CallServerInterceptor.记住source 是读入流,sink属于写入流。

  @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();
    //注意前面的赋值在ConnectInterceptor 里面,HttpCodec 现在是HttpCodec1。
    //到这里代表socket已经正式建立了连接。现在只需要通过Http协议与Server进行交互了。
    long sentRequestMillis = System.currentTimeMillis();
    
    realChain.eventListener().requestHeadersStart(realChain.call());
    // 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;
 // }
 // 通过我之前分析的拿到sink以后就可以写入RequestHeader 逻辑essay。
    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.
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        realChain.eventListener().responseHeadersStart(realChain.call());
        responseBuilder = httpCodec.readResponseHeaders(true);
      }
       // 100-continue 就是询问服务器是否处理Post数据,如果处理走下面的逻辑。 
      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);
        // 对于POST,body为FormBody。写入RequetBody内容。
        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();
      }
    }
    //HttpCodc1 持有sink和source,完成请求。
    httpCodec.finishRequest();

    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }
    //实际这个是读取两次这个Response,这是地此意,读取到这个code=100
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();
    //code=100 代表读取正常,可以
    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 {
    //实际读取到ResposeBody。实际上openResonseBody也是通过source,read byte转换为ResponseBody,到这里我们就获取到结果了。返回到response。
      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;
  }

这里CallServerInterceptor就分析完了,没有分析太深入,后续有机会再次深入去了解吧,都是一些http请求的细节了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值