Okhttp之BridgeInterceptor阻拦器解析

作者 : 开心源码 本文共4343个字,预计阅读时间需要11分钟 发布时间: 2022-05-12 共141人阅读

假如研究过okhttp源码,应该知道okhttp的核心是阻拦器,而阻拦器所采用的设计模式是责任链设计,即每个阻拦器只解决与自己相关的业务逻辑。

之前已经分析了Okhttp的RetryAndFollowUpInterceptor的原理。

阻拦器的核心代码都在intercept(Chain chain )方法中,所以有必要彻底研究该方法是如何解决就可了解BridgeInterceptor的作用和实现。

1、okhttp中RealCall中请求网络及增加阻拦器的核心代码

如下是okhttp中RealCall.java文件中的将一个request请求,得到response的核心代码,getResponseWithInterceptorChain(),即一进方法就增加了好几个阻拦器。

  Response getResponseWithInterceptorChain() throws IOException {    // Build a full stack of interceptors.    List<Interceptor> interceptors = new ArrayList<>();    interceptors.addAll(client.interceptors());    interceptors.add(retryAndFollowUpInterceptor);    interceptors.add(new BridgeInterceptor(client.cookieJar()));    interceptors.add(new CacheInterceptor(client.internalCache()));    interceptors.add(new ConnectInterceptor(client));    if (!forWebSocket) {      interceptors.addAll(client.networkInterceptors());    }    interceptors.add(new CallServerInterceptor(forWebSocket));    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,        originalRequest, this, eventListener, client.connectTimeoutMillis(),        client.readTimeoutMillis(), client.writeTimeoutMillis());    return chain.proceed(originalRequest);  }

2、 开始分析之前,先来理解一下正常的一次网络请求过程

一次Http请求必需要携带少量特定的Header信息,例如:以请求百度主页为例,Request中携带的信息如下:

request.png

额,貌似有点看不清,看下图,是不是高清无码

request头信息.png
标红的这些字段,即Header信息必要字段,水了这么多,就是为了说明白,一次http网络请求并不是只要要设置一个地址即可以,而是要封装一个特定的格式和必要的参数(即Header信息)。

3、BridgeInterceptor的核心伪代码

有了上面的这思想,看BridgeInterceptor的核心伪代码,是不是恍然大悟了!(具体方法作用都表明了注释)

public final class BridgeInterceptor implements Interceptor {  private final CookieJar cookieJar;  public BridgeInterceptor(CookieJar cookieJar) {    this.cookieJar = cookieJar;  }  @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) {        //增加Content-Length头信息        requestBuilder.header("Content-Length", Long.toString(contentLength));        requestBuilder.removeHeader("Transfer-Encoding");      } else {        requestBuilder.header("Transfer-Encoding", "chunked");        requestBuilder.removeHeader("Content-Length");      }    }    //增加Host信息    if (userRequest.header("Host") == null) {      requestBuilder.header("Host", hostHeader(userRequest.url(), false));    }    //增加Connection信息    if (userRequest.header("Connection") == null) {      requestBuilder.header("Connection", "Keep-Alive");    }    //增加 Accept-Encoding信息    boolean transparentGzip = false;    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {      transparentGzip = true;      requestBuilder.header("Accept-Encoding", "gzip");    }    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());    //增加Cookie头信息    if (!cookies.isEmpty()) {      requestBuilder.header("Cookie", cookieHeader(cookies));    }     //增加User-Agent信息    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);    //假如服务器返回的response是压缩过的,即获取GzipSource输入流,读取返回的数据    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();  }//返回并封装为key=value 形式的cookie信息  private String cookieHeader(List<Cookie> cookies) {    StringBuilder cookieHeader = new StringBuilder();    for (int i = 0, size = cookies.size(); i < size; i++) {      if (i > 0) {        cookieHeader.append("; ");      }      Cookie cookie = cookies.get(i);      cookieHeader.append(cookie.name()).append('=').append(cookie.value());    }    return cookieHeader.toString();  }}

3.1 方法注释已增加到method上

即获取到客户创立request对象,而后在该基础上增加http请求必要的头信息。假如返回的response信息是压缩后的,在通过okio压缩输入流解决response。

3.2 再来看看构造方法中传入的CookieJar

public BridgeInterceptor(CookieJar cookieJar) 

构造中穿传入的CookieJar,会通过cookieHeader()方法,封装为key=value的形式,增加到Header信息中的cookie字段中。

4、总结一下BridgeInterceptor的作用:

4.1 封装request头信息
4.2 解决cookie信息
4.3 解决服务器压缩后的response

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Okhttp之BridgeInterceptor阻拦器解析

发表回复