OkHttp-(二)Interceptor以及对应的责任链模式

前言

对于客户端来说,网络请求就是发送一个Request,得到一个Response的过程;很多的网络请求框架都会对这个过程进行封装处理,减少我们对内部逻辑的了解以及用少量的代码完成整个请求流程。不同公司的网络请求定义格式不一样,就需要我们的网络请求框架能够更灵活的扩展,从而在不改变源码的情况下,完成业务的需求。比如在请求过程,对请求的数据统一加解密处理,不同的业务,设置不同的Header,日志拦截等等。对OKHttp而言,就很好的考虑到这些需求,对Request和Response提供了责任链的模式的Interceptor供我们开发中灵活扩展,其中一些必须的Interceptor已经在内部实现,自动添加。下面就了解OKHttp是如何实现这种灵活扩展的。

OkHttp的Request和Response简易流程

    OkHttpClient okHttpClient = new OkHttpClient();
    String url = "https://publicobject.com/helloworld.txt";
    Request request = new Request.Builder()
            .url(url)
            .build();
    Response response = okHttpClient.newCall(request).execute();
    

这里的示例代码说了客户如何发送一个Request和得到一个Response的流程,使用起来很简单,内部的实现细节和流程OkHttp已往我们完成。下面看一下源码的RealCall的execute()方法做了哪些操作。

  @Override 
  public Response execute() throws IOException {
    ...省略部分代码...
    try {
      client.dispatcher().executed(this);
      //此处返回Response
      return getResponseWithInterceptorChain();
    } finally {
      client.dispatcher().finished(this);
    }
  }

接下来看一下getResponseWithInterceptorChain()做了哪些操作:

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    //添加自定义的Intercepttor
    interceptors.addAll(client.interceptors());
    //添加系统内部的Interceptor,统一添加到List中
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    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, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
      //获取Response
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }

这里的Response是通过RealInterceptorChain的procedd()方法返回的,接下来看一下chain的proceed()方法做了哪些操作。


  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, transmitter, exchange);
  }

  public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
      throws IOException {
    ...省略部分代码...
    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    //获取拦截器
    Interceptor interceptor = interceptors.get(index);
    //调用拦截器的intercept方法进行处理
    Response response = interceptor.intercept(next);

   ....省略部分代码...

    return response;
  }

这里已经出现了Interceptor和Chain的影子,接下来了解具体的实现过程。

Intercptor和Chain在OkHttp中的内部实现

Interptor和Chain的内部定义,这里对Interceptor的描述主要意思是可以对Request和Response进行处理。

/**
 * Observes, modifies, and potentially short-circuits requests going out and the corresponding
 * responses coming back in. Typically interceptors add, remove, or transform headers on the request
 * or response.
 */
public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;
    ...省略部分代码...
   
  }
}

从发出一个Request到得到一个Response,中间都需要经过一些处理,完成Http协议的相关内容设置,最终再由Socket的OutputStream和InputStream完成读写,完成整个流程。这些中间层的处理由相应Interceptor来完成,让代码结构更新清晰,同时也满足了我们的单一职责原则。比如:RetryAndFollowUpInterceptor,负责完成重试机制;BridgeInterceptor,完成Http协议中一些默认Header的添加;CacheInterceptor,处理我们的请求可以拿缓存数据还是需要从服务拉取数据;ConnectInterceptor,负责处理请求的Connection;CallServerInterceptor,负责最终与服务端的交互处理。从发出一个Request到返回Response,则需要完成一个链式的调用流程,将相关的Interceptor组成一条链,再后RealInterceptorChain来完成责任链的流程。因此Request到Response的设计采用责任链的模式更合理和更加容易灵活扩展。
下面给出一个Chain的处理图:
image

接下来看一下内部是如何完成链式调用流程的,在ReallCall的getResponseWithInterceptorChain()方法中,初始化RealInterceptorChain,默认处理List中的第0个

 Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    .......
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
    try {
      //处理请求
      Response response = chain.proceed(originalRequest);
    }
    ...省略部分代码...
  }

接下来看chain.procced()的内部实现


  public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
      throws IOException {
    ...省略部分代码...
    // Call the next interceptor in the chain.
    //实例化一个新的RealInterceptorChain,index+1指向下一个Interceptor
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    //取出当前Interceptor,并调用其对应的intercept()方法。
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
   ...省略部分代码...
    return response;
  }

这里我们不添加自定义Interceptor的情况下,List中包含了Intercptor依次为RetryAndFollowUpInterceptor,BridgeInterceptor,CacheInterceptor,ConnectInterceptor,CallServerInterceptor。在getResponseWithInterceptorChain()方法中,index为0,因此取出的第一个Interceptor为RetryAndFollowUpInterceptor,同时实例化指向下一个Interceptor的的chain。我们看一下RetryAndFollowUpInterceptor的interceptor做了什么操作:

public final class RetryAndFollowUpInterceptor implements Interceptor {
    ......
    
   @Override
   public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    ...省略部分代码...
    while (true) {
      ......
      Response response;
      boolean success = false;
      try {
        //调用chain.proceed方法,执行下一个Interceptor
        response = realChain.proceed(request, transmitter, null);
        success = true;
      } 
      ......

    }
}
    
}

在RetryAndFollowUpInterceptor的intercept()方法中调用RealInterceptorChain.procced方法,紧接着执行BridgeInterceptor的intercept()方法

public final class BridgeInterceptor implements Interceptor {

    @Override public Response intercept(Chain chain) throws IOException {
        Request userRequest = chain.request();
        Request.Builder requestBuilder = userRequest.newBuilder
        
        ......
        //调用chain.proceed方法,执行下一个Interceptor
        Response networkResponse = chain.proceed(requestBuilder.build());
        
        ......
        
    }
    
}

其他的Interceptor的处理类似,这里面能够直接返回Response的分别是CacheInterceptor和CallServerInterceptor,在CacheInterceptor中,如果符合要求,可直接返回cacheResponse,不在执行 chain.proceed()方法,否则,继续执行后面的Interceptor,最终执行到CallServerInterceptor,请求服务器获取数据,返回Response。

OkHttp中的Chain的用法和我们和经典的责任链模式的使用方法略有不同。在经典责任链模式中,我需要手动设置nextHandler;在OkHttp中,我们只需要将Interceptor添加到OkHttpClient中,由内部帮我们维护责任链的上下连接关系。这里具体在RealInterceptorChain的proceed()方法中处理。
对于网络来讲,Request在链中是一种平级关系,每个Interceptor都可以根据自己的需要对Request处理,拿到Response后更具需要进行处理后,再将Response返回给上一个Interceptor。

小结

  1. OkHttp中Interceptor的灵活设计,使得我们可以在不修改源码的基础上对Request和Response进行很多灵活处理,比如日志输出,可用添加自定义LogInterceptor;双Token的刷新可以添加自定义的RefreshInterceptor;项目中不同的请求使用不同的地址,可自定义DomainInterceptor等等。

  2. OkHttp中责任链模式的设计与经典责任链模式的不同,可以减少我们在自定义Interceptor时由于对内部原理不熟悉的情况下犯错误的可能。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值