Okhttp之CallServerInterceptor拦截器原

作者: OneXzgj | 来源:发表于2019-01-19 16:37 被阅读9次

    在开始之前拓展一个http的知识:

    1、关键字100-continue介绍

    http 100-continue用于客户端在发送POST数据给服务器前,征询服务器情况,看服务器是否处理POST的数据,如果不处理,客户端则不上传POST数据,如果处理,则POST上传数据。在现实应用中,通过在POST大数据时,才会使用100-continue协议。

    2、客户端策略

    • 如果客户端有POST数据要上传,可以考虑使用100-continue协议。加入头{"Expect":"100-continue"}
    • 如果没有POST数据,不能使用100-continue协议,因为这会让服务端造成误解。
    • 并不是所有的Server都会正确实现100-continue协议,如果Client发送Expect:100-continue消息后,在timeout时间内无响应,Client需要立马上传POST数据。
    • 有些Server会错误实现100-continue协议,在不需要此协议时返回100,此时客户端应该忽略。

    3、服务端策略

    • 正确情况下,收到请求后,返回100或错误码。
    • 如果在发送100-continue前收到了POST数据(客户端提前发送POST数据),则不发送100响应码(略去)。

    回到CallServerInterceptor核心Intercept方法:

      @Override public Response intercept(Chain chain) throws IOException {
        ...
    
        //封装请求头,即conent-length,method,编码等等
        realChain.eventListener().requestHeadersStart(realChain.call());
        httpCodec.writeRequestHeaders(request);
        realChain.eventListener().requestHeadersEnd(realChain.call(), request);
    
        //当前request需要请求体,即post请求等方式,如果有,则进行封装
        Response.Builder responseBuilder = null;
        if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
          // 判断服务器是否允许发送body
          if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
            httpCodec.flushRequest();
            realChain.eventListener().responseHeadersStart(realChain.call());
            responseBuilder = httpCodec.readResponseHeaders(true);
          }
    
          if (responseBuilder == null) {
            // 向服务器发送requestbody,
            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);
            ....
        }
    
        //结束请求
        httpCodec.finishRequest();
    
        if (responseBuilder == null) {
          realChain.eventListener().responseHeadersStart(realChain.call());
          responseBuilder = httpCodec.readResponseHeaders(false);
        }
    
        //返回response
        Response response = responseBuilder
            .request(request)
            .handshake(streamAllocation.connection().handshake())
            .sentRequestAtMillis(sentRequestMillis)
            .receivedResponseAtMillis(System.currentTimeMillis())
            .build();
    
          //100的状态码的处理继续发送请求,继续接受数据
        int code = response.code();
        if (code == 100) {
          responseBuilder = httpCodec.readResponseHeaders(false);
    
          response = responseBuilder
                  .request(request)
                  .handshake(streamAllocation.connection().handshake())
                  .sentRequestAtMillis(sentRequestMillis)
                  .receivedResponseAtMillis(System.currentTimeMillis())
                  .build();
          code = response.code();
        }
    
        ...
        //返回为空的处理
        if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
          throw new ProtocolException(
              "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
        }
        return response;
      }
    
    

    简单概述一下流程:

    1、获取到 ConnectInterceptor 拦截器中的httpCodec和realChain,至于ConnectInterceptor中做了什么,可以看之前写的《Okhttp之ConnectInterceptor拦截器原理及解析》

    2、写入http请求头信息,判断是否允许上传requestBody

    1. 判断header中Expect域是否为100-continue,这个请求头字段的作用是在发送RequestBody前向服务器确认是否接受RequestBody,如果没有,则正常请求。如果有,则相当于一次简单的握手操作,则等待服务器返回的ResponseHeaders之后再继续,如果服务器接收RequestBody,会返回null。

    2. 根据3的判断,如果RequestBuilder为null,说明Expect不为100-continue或者服务器同意接收RequestBody。这时就开始向流中写入RequestBody。

    3. 读取响应头信息 构建Response,写入原请求、握手情况、请求时间、得到结果的时间等

    4. 针对204/205状态码处理

    5. 返回Response

    相关文章

      网友评论

        本文标题:Okhttp之CallServerInterceptor拦截器原

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