OkHttp 源码分析(三)——BridgeInterceptor

上一篇文章中,我们简单分析了OkHttp的第一个拦截器RetryAndFollowUpInterceptor的处理流程,主要工作是创建了一个streamAllocation,并将streamAllocation和request传给下一个拦截器:BridgeInterceptor进行处理,并根据网络请求中的异常或响应结果判定是否需要进行重连。

所以,今天我们来分析BridgeInterceptor这个拦截器的处理流程。

简介

 BridgeInterceptor,中文翻译过来即是桥接拦截器,这个拦截器的主要功能是将上一个拦截器传过来的request进行请求头处理,将协议必要的头部信息和用户定义的头信息合并,然后交由下一个拦截器进行处理,获取到Response后进行cookies和gzip处理。

源码Request部分

废话不多说,直接看BridgeInterceptor的intercept方法:

public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();

    RequestBody body = userRequest.body();
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {
        //设置实体主体的媒体类型
        requestBuilder.header("Content-Type", contentType.toString());
      }
        //实体主体的大小(单位:字节
      long contentLength = body.contentLength();
      if (contentLength != -1) {
        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");
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }
    //获取cookies
    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }
    //http客户端程序信息
    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }
    //调用下一个拦截器
    Response networkResponse = chain.proceed(requestBuilder.build());

   
  }

这一段我们看到BridgeInterceptor这个拦截器主要对Request做了添加请求头字段的操作,将用户构建的Request请求转化为符合http协议的、能够进行网络访问的请求,然后再将此Request传递给下一个拦截器。

源码Response部分

接上面获取到Response后:

    Response networkResponse = chain.proceed(requestBuilder.build());

    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);

    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();

在拿到下一个拦截器返回的Response后,首先 通过HttpHeaders.receiveHeaders进行cookies处理保存cookies信息:

public static void receiveHeaders(CookieJar cookieJar, HttpUrl url, Headers headers) {
    //如果用户没有配置自定义cookies则返回
    if (cookieJar == CookieJar.NO_COOKIES) return;
    //解析
    List<Cookie> cookies = Cookie.parseAll(url, headers);
    if (cookies.isEmpty()) return;
    //存储cookies
    cookieJar.saveFromResponse(url, cookies);
  }

在前面Request部分,我们有看到获取cookies的方法过程:

 List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

 CookieJar只是一个接口,我们要在程序中进行cookies操作时,一般就是实现这个接口,并添加到OkhttpClient中去

OkHttpClient client = new OkHttpClient.Builder()
                        .cookieJar(new CookieJar() {
                            @Override
                            public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                                //在此保存cookie,如使用SharedPreferences等
                            }

                            @Override
                            public List<Cookie> loadForRequest(HttpUrl url) {
                                //读取cookies,
                                List<Cookie> cookieList = new ArrayList<>();
                                //...
                                return cookieList;
                            }
                        })
                        .build();

接着,对拿到的Response判断服务器是否对响应体进行了Gzip压缩,如果进行了Gzip压缩,则需要进行Gzip解压(基于Okio),最后重新构建Response并返回给上一个拦截器。

总结

这一节我们简单解析了BridgeInterceptor的处理逻辑,整体流程还是比较简单的:

  1.  将用户构建的Request请求转化成能够进行网络访问的请求(请求头设置、cookies读取等)

  2.  将请求传递给下一个拦截器,并获取响应;

  3.  对响应进行处理(cookies处理、gzip解压等),将响应转化成用户可用的Response,返回给上级拦截器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值