美文网首页
ConnectInterceptor&CallServerInt

ConnectInterceptor&CallServerInt

作者: 嗯哼嗯哼嗯哼嗯哼 | 来源:发表于2019-11-25 11:19 被阅读0次

    OkHttp

    关于OkHttp最精华的部分其实就是拦截器链的设计,这篇文章就分析ConnectInterceptor和CallServerInterceptor两个拦截器,主要是为了串联起来之前讲过的。

    拦截器

    OkHttp中的核心就是在RealCall中的getResponseWithInterceptorChain()方法

      Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors());
        interceptors.add(retryAndFollowUpInterceptor);
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        interceptors.add(new CacheInterceptor(client.internalCache()));
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
          interceptors.addAll(client.networkInterceptors());
        }
        interceptors.add(new CallServerInterceptor(forWebSocket));
    
        Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
            originalRequest, this, eventListener, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());
    
        return chain.proceed(originalRequest);
      }
    

    根据上面代码,用户自定义的拦截器从位置上会分为两种,一种是普通拦截器,一种是网络拦截器。两个唯一的区别就是在拦截器链的位置不一样,具体的区分是网络拦截器在建立网络连接之后,在拦截器的最后部分,下一步就是向服务器发送数据了,最后一个拦截器是CallServerInterceptor

    ConnectInterceptor

    建立网络连接的地方

      @Override public Response intercept(Chain chain) throws IOException {
       RealInterceptorChain realChain = (RealInterceptorChain) chain;
       Request request = realChain.request();
       StreamAllocation streamAllocation = realChain.streamAllocation();//这个StreamAllocation是在RetryAndFollowUpInterceptor中创建出来的
    
       // We need the network to satisfy this request. Possibly for validating a conditional GET.
       boolean doExtensiveHealthChecks = !request.method().equals("GET");
       HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);//建立网络连接,得到和服务器传输的数据流HttpCodec
       RealConnection connection = streamAllocation.connection();
    
       return realChain.proceed(request, streamAllocation, httpCodec, connection);
     }
    

    在HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);这里会建立网络连接,得到和服务器传输的数据流HttpCodec,这里其实就是涉及到连接的建立,复用,流的创建的逻辑。是Connection,ConnectionPool,StreamAllocation在发起网络流程中主要的逻辑入口

    在ConnectInterceptor拦截器中,只是与服务端建立连接,得到输入输出流。按照上面的分析,如果有网络拦截器的话,就会在这之后执行网络拦截器,最后再执行CallServerInterceptor与服务器进行交互。

    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());
        httpCodec.writeRequestHeaders(request);//向服务器写入请求头
        realChain.eventListener().requestHeadersEnd(realChain.call(), request);
    
        Response.Builder responseBuilder = null;
        if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
          
            .....
          if (responseBuilder == null) {
          .....
            //写入请求体
            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();
    
        //读取响应头
        if (responseBuilder == null) {
          realChain.eventListener().responseHeadersStart(realChain.call());
          responseBuilder = httpCodec.readResponseHeaders(false);
        }
    
        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;
      }
    

    从上面的代码可以看的出来,在CallServerInterceptor拦截器中,主要就是执行4步操作,可能其中有的操作会没有,但是主要是这4步

    1. 写请求头
    2. 写请求体
    3. 读响应头
    4. 读响应体

    相关文章

      网友评论

          本文标题:ConnectInterceptor&CallServerInt

          本文链接:https://www.haomeiwen.com/subject/dhpdwctx.html