okhttp Interceptor责任链

okhttp Interceptor责任链

责任链

责任链模式将处理用户请求的对象形成一个链,责任链上的每个处理者要么处理用户的请求,要么把请求传递给责任链上的下一个处理者

实例:

  1. 请求
  2. 处理者:处理请求的对象
  3. 链:处理者形成的链表

说明:

  1. 一个请求交给链表上第一个处理者处理
  2. 第一个处理者处理不了,交由下一个处理者
  3. 如果链上某一处理者能够处理,则直接返回处理结果,不再交由后面的处理者处理
  4. 如果最后一个处理者也无法处理,则返回无效的结果
  5. 后面处理者处理的结果,前面的处理者也可以操作。

RealCall.getResponseWithInterceptorChain()

源码:

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    // 构造Interceptor栈
    List<Interceptor> interceptors = new ArrayList<>();
    // 添加配置的Interceptor
    interceptors.addAll(client.interceptors());
    // 下面添加逻辑处理的的Interceptor
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    // 添加配置的networkInterceptor,不是长连接才添加
    if (!forWebSocket) &#123;
        interceptors.addAll(client.networkInterceptors());
    &#125;
    // 添加真正执行的网络连接的Interceptor
    interceptors.add(new CallServerInterceptor(forWebSocket));

    // 构造Interceptor链
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
            originalRequest, this, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());

    // 标记请求是否抛出异常
    boolean calledNoMoreExchanges = false;
    try &#123;
        // 执行Interceptor责任链
        Response response = chain.proceed(originalRequest);
        // 若在执行过程前已经关闭了,则关闭Response并抛出异常
        if (transmitter.isCanceled()) &#123;
            closeQuietly(response);
            throw new IOException("Canceled");
        &#125;
        // 返回结果
        return response;
    &#125; catch (IOException e) &#123;
        // 标记发生了异常,抛出异常,并申请关闭连接
        calledNoMoreExchanges = true;
        throw transmitter.noMoreExchanges(e);
    &#125; finally &#123;
        // 若未发生异常,申请关闭连接
        if (!calledNoMoreExchanges) &#123;
            transmitter.noMoreExchanges(null);
        &#125;
    &#125;
&#125;

下面是Interceptor责任链流程图

Interceptor 责任链

在这个链表中,可以直接自行处理Request得到Response,不交由下一级处理者的Interceptor有:CacheInterceptorCallServerInterceptor。其他的Interceptor用于其他处理,如ConnectInterceptor用于连接服务器。

下面分别分析这些Interceptor的作用

RetryAndFollowUpInterceptor

This interceptor recovers from failures and follows redirects as necessary. It may throw an {@link IOException} if the call was canceled.

翻译:这个Interceptor用于失败重试和必要时重定向。如果Call被取消,可能会抛出IOException

具体我就不深入代码了,这更多的涉及HTTP协议的相关内容,其实知道这个类的作用就行了。可以简单的了解几点:

  1. 重定向最大次数为20次,Chrome是21次,Firefoxcurlwget是20次,Safari是16次,HTTP/1.0推荐是5次。
  2. 不能重试的情况
    • 应用层禁止重试
    • 无法发送RequestBody:只有当RequestBody是被缓存的(Buffered)才能重试(可能RequestBody是一次性的)
    • 无法恢复的异常,如ProtocolException协议异常
    • 没有更多的线路去重试

BridgeInterceptor

Bridges from application code to network code. First it builds a network request from a user request. Then it proceeds to call the network. Finally it builds a user response from the network response.

翻译:应用层代码和网络层代码的桥梁。首先它从用户请求构建一个网络层的Request,然后它交由网络层处理,最后从网络层的Response处理得到一个应用层的Response

这段话很直接,实际上,它处理传送过来的应用Request,添加一些参数,然后对交由网络层处理得到的Response再进一步处理,返回给应用层。

BridgeInterceptorRequest的处理:

  1. 如果有请求体RequestBody,则根据请求体内容,添加headerContent-TypeContent-LengthTransfer-Encoding
  2. header中添加Host
  3. header中没有Connection,则设置为Keep-Alive
  4. header中没有Accept-EncodingRange,设置Accept-Encodinggzip
  5. 添加cookie
  6. 添加User-Agent

BridgeInterceptorResponse的处理:

  1. 复制网络层的Response内容,得到新的Response
  2. 处理cookie
  3. 处理gzip响应结果

CacheInterceptor

Serves requests from the cache and writes responses to the cache.

翻译:使用缓存处理请求,将结果写入缓存。

字面意思很简单。下面是需要注意的点:

  1. 如果只能从配置了只能从Cache中获取结果,但是没有缓存结果,将返回504错误。
  2. 如果可以从缓存中获取数据,并且有缓存,则直接返回缓存数据
  3. 进行网络请求,如果返回304表示结果与上次请求相同,返回缓存结果,同时更新缓存。
  4. 如有必要,将得到的网络请求结果,写入缓存

可以看出,CacheInterceptor是可以处理Request得到Response的,如果可以,不必交由下一个Interceptor进行处理。

ConnectInterceptor

Opens a connection to the target server and proceeds to the next interceptor.

翻译:为目标服务器打开一个连接Connection,并且交由下一个Interceptor进行处理。

从这段话就可以看出ConnectIntercetpor则不产生直接结果。并且只是用于建立连接。

CallServerInterceptor

This is the last interceptor in the chain. It makes a network call to the server.

翻译:这是链中最后一个Interceptor。它向服务器发送一个网络请求。

它实际完成的工作:

  1. 写入请求头
  2. 写入请求体
  3. 读取请求头
  4. 读取请求体
  5. 处理请求结果

除了控制逻辑之外,实际处理请求的是Exchange

Exchange

Transmits a single HTTP request and a response pair. This layers connection management and events on {@link ExchangeCodec}, which handles the actual I/O.

翻译:发送单独HTTP Request-Response对。它将连接层管理与事件分层,ExchangeCodec处理真实的IO操作。

ExchangeCodec

Encodes HTTP requests and decodes HTTP responses.

翻译:编码HTTP请求,解码HTTP响应。

实际上就是转换对象/实例与HTTP协议内容。

总结

这样子分别理清所有Interceptor的功能,一下就豁然开朗了。不需要在意代码细节,整个流程真的是非常的漂亮。我在编码,而OkHttp的开发者是在做艺术。

同时,我们通过OkHttpClient添加的interceptornetworkInterceptor分别是在RetryAndFollowUpInterceptorCallServerInterceptor之前。所以可以明白:

  1. 如果使用的是缓存,则interceptor可以被调用到,而networkdInterceptor是不会调用到的
  2. 我们通常可以在networkInterceptor中进行一些特殊的处理,如access token过期时,使用refresh token刷新access token,配合Requesttag可以区分普通请求和刷新access token请求
  3. 我们可以在interceptor中加密数据
  4. 甚至我们可以自己返回Response,拦截责任链。

   转载规则


《okhttp Interceptor责任链》 Mycroft Wong 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
okhttp Interceptor接口 okhttp Interceptor接口
okhttp Interceptor接口前言前面一直在说Interceptor责任链,那Interceptor到底是什么呢 Interceptor Observes, modifies, and potentially short-circ
下一篇 
okhttp请求与响应执行过程 okhttp请求与响应执行过程
okhttp请求与响应执行过程前言不考虑真正的网络请求部分,看一下从一个Request到Response的过程。 请求再来看一下上一篇最简单的执行代码 OkHttpClient httpClient = new OkHttpClient.B
  目录