OkHttp源码解析(三)请求响应转换

Android框架学习

Posted by Cc1over on January 11, 2020

OkHttp源码解析(三)请求响应转换

BridgeInterceptor-> intercept

 @Override public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    // 构建一个新的Builder 
    Request.Builder requestBuilder = userRequest.newBuilder();
    
    RequestBody body = userRequest.body();
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {
        // 把ContentType这个枚举转换为String  
        requestBuilder.header("Content-Type", contentType.toString());
      }
       
      long contentLength = body.contentLength();
      if (contentLength != -1) {
        // ContentLength转换为String  
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }
    }
    
    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }
    
    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }

    // 如果还没设置Accept-Encoding,自动设置gzip
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }
    // 把原请求中的cookie设置到新的builder中
    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      // 把Cookie转换成String  
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }
    // 从下层拿到Response
    Response networkResponse = chain.proceed(requestBuilder.build());
    
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
    // 构建一个新的Response用做转换,理所当然的把request设置为转换前的Request
    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);
    // 如果设置了Gzip压缩,则要进行Gzip解压
    if (transparentGzip
        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
        && HttpHeaders.hasBody(networkResponse)) {
      GzipSource responseBody = new GzipSource(networkResponse.body().source());
      Headers strippedHeaders = networkResponse.headers().newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build();
      responseBuilder.headers(strippedHeaders);
      String contentType = networkResponse.header("Content-Type");
      responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
    }

    return responseBuilder.build();
  }

将用户构建的Request请求转化为一个能够进行网络传输的请求,所以这里需要枚举、long向String的转换

将Request交给下一个拦截器,然后拿到一个Response

然后最后就是将网络请求可用的Response转换为用户可用的Response

这是因为调用的时候构建一个Request,只是简单把url、参数设置进来,但是实际上,实际做网络传输还需要其他的一些请求头:

  • Content-Type:网络请求类型
  • Content-Length:请求体内容的长度,与 Transfer-Encoding互斥
  • Transfer-Encoding: 值为 chunked 表示请求体的内容大小是未知的,与 Content-Length 互斥
  • Host: 请求的 url 的主机
  • Connection: 默认就是 Keep-Alive,就是一个 TCP 连接之后不会关闭,保持连接状态
  • Accept-Encoding: 默认是 gzip,告诉服务器客户端支持 gzip 编码的响应
  • Cookie: 当请求设置了 Cookie 那么就是添加 Cookie 这个请求头
  • User-Agent: 根据 OkHTTP 的版本来返回