okhttp3-源码分析(4) BridgeInterceptor

BridgeInterceptor是位于重定向拦截器之后的第一个拦截器,也就是说在okhttp默认实现的5个拦截器中的第二个。
他的作用,顾名思义就是用户程序层面和网络层面的桥梁。他会根据用户请求来构建真正要用到的网络请求,又会根据服务器返回的网络请求,来构建用户层面的请求。
从源代码分析,以小一点的视角看,他其实主要就是对请求报文的首部行做一些的设置,对响应报文可能出现需要解压文件的情况,进行解压。
另一方面,okhttp中对cookie的相关设置也在这个拦截器中完成,okhttp是默认不使用cookie的,如果要添加cookie,需要我们在构建okhttpclient中自己实现相应的接口。

源码分析

BridgeInterceptor的代码其实并不复杂,更主要的是需要我们对http报文格式有深入的理解,才能理解BridgeInterceptor的工作流程。

 //直接看intercept方法
  @Override public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();//获取chain上传递的request
    Request.Builder requestBuilder = userRequest.newBuilder();
      //设置request的builder(用来生成真正用于网络层面的request)
      
    RequestBody body = userRequest.body();//还是应用程序层面的request
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {//设置contentType,指示http中entity body的类型
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {//使用content-length指示被发送对象的字节数
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {//使用分块运输,不需要content-length
        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");
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    //机翻:如果我们添加一个“Accept-Encoding: gzip”头域,我们还负责解压传输流。  
      
    boolean transparentGzip = false;//所以这里要加一个指示器,后面可能要解析
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {//Accept-Encoding和要不要压缩有关,Range和断点续传有关,这里的条件还不是很明白
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");//希望服务器发送压缩的response
    }
	
      //这里的cookie操作,需要我们自己传入cookieJar(在设置okhttp-client的时候)
    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {//添加cookie
      requestBuilder.header("Cookie", cookieHeader(cookies));
  // cookieHeader这个方法不太复杂,就是遍历缓存把header取出来,这里就不放这个方法的详细实现了
    }

    if (userRequest.header("User-Agent") == null) {//指明用户代理(向服务器发请求的浏览器类型)
      requestBuilder.header("User-Agent", Version.userAgent());//默认是okhttp/3.12.0
    }

    Response networkResponse = chain.proceed(requestBuilder.build());
      //交给下一个拦截器处理request

    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
	//这部分是对cookie进行处理,同样也要自己设置了cookie,才能触发
    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);//配置response

    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)));//对body设置
    }

    return responseBuilder.build();//返回response
  }

你可能感兴趣的:(Android网络框架,java,网络协议,http,android)