美文网首页网络请求Android开发android技术专栏
关于Okhttp3(五)-BridgeInterceptor

关于Okhttp3(五)-BridgeInterceptor

作者: lowett | 来源:发表于2017-03-02 10:25 被阅读125次

    上一篇我们讲了Okhttp3请求你流程中的第一个拦截器BridgeInterceptor,其中初始化好一个socket连接对象后,随即将进行下一个流程,即今天要讲的BridgeInterceptor(桥接拦截)。

    功能

    本拦截器的主要功能是:处理请求头(header),将自定义的头和协议必须的头合在一起,如果有自定义使用自定义的,没有就生成默认头

    源码

    // 主要方法,其他略
    // 此拦截器较为简单,其中有两点比较重要,1、cookie的处理 2、Gzip
    @Override 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");
      }
    
      // 创建Okhpptclitent时候配置的cookieJar,
      List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
      if (!cookies.isEmpty()) {
        requestBuilder.header("Cookie", cookieHeader(cookies));
      }
    
      // 默认的是 okhttp3/3.0.1,即版本号
      if (userRequest.header("User-Agent") == null) {
        requestBuilder.header("User-Agent", Version.userAgent());
      }
    
      //  以上为请求前的头处理
      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);
        responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
      }
    
      return responseBuilder.build();
    }
    

    获取本地的cookie

    // 源码部分,略
    // 创建Okhpptclitent时候配置的cookieJar,
      List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    // 所以返回的cookies不能为空,否则这里会报空指针
      if (!cookies.isEmpty()) {
        // 解析成http协议的cookie格式
        requestBuilder.header("Cookie", cookieHeader(cookies));
      }
    

    此处就是获取本地的cookie,调用cookieJar.loadForRequest()方法,前文关于Okhttp(一)-基本使用有说过:

     OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .cookieJar(new CookieJar() {
                        @Override
                        public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                            // 保存cookie通常使用SharedPreferences
                        }
    
                        @Override
                        public List<Cookie> loadForRequest(HttpUrl url) {
                          // 从保存位置读取,注意此处不能为空,否则会导致空指针
                            return new ArrayList<>();
                        }
                    })
                    .build();
    

    解析服务器返回的Header

    // 响应header, 如果没有自定义配置cookie不会解析
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
    
    public static void receiveHeaders(CookieJar cookieJar, HttpUrl url, Headers headers) {
      // 没有配置,不解析
      if (cookieJar == CookieJar.NO_COOKIES) return;
    
      // 此处遍历,解析Set-Cookie的值,比如max-age
      List<Cookie> cookies = Cookie.parseAll(url, headers);
      if (cookies.isEmpty()) return;
    
      // 然后保存,即自定义
      cookieJar.saveFromResponse(url, cookies);
    }
    

    cookie的处理比较简单,重要的是要理解http协议。

    Gzip

    okhttp3支持gzip压缩,本事不负责处理,而是交给以来库Okio处理

    // 略部分代码
    // 前面解析完header后,判断服务器是否支持gzip压缩格式,如果支持将交给Okio处理,至于okio如何处理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);
      // 处理完成后,重新生成一个response
      responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
    }
    

    至此,BridgeInterceptor的功能就说完了,是不是很简单。

    总结

    Okhttp3本事有5个重要的拦截器,到这里我们讲了2个,下一篇将介绍平日说的比较多的,也是比较重要的一个,与缓存相关的拦截器,敬请期待。

    系列文章

    1. 关于Okhttp(一)-基本使用
    2. 关于Okhttp(二)-如何下载查看源码
    3. 关于Okhttp3(三)-请求流程
    4. 关于Okhttp3(四)-RetryAndFollowUpInterceptor
    5. 关于Okhttp3(五)-BridgeInterceptor

    相关文章

      网友评论

        本文标题:关于Okhttp3(五)-BridgeInterceptor

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