OkHttp(三) - 拦截器链处理过程分析

1,762 阅读4分钟

前面分析了请求的具体执行流程,请求最终会经过一个由多个拦截器组成的链条来处理具体的请求和响应,这个便是我们熟知的调用链(责任链)模式

责任链模式


责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。如图所示:

上图形象地描述了责任链模式的工作状态,这里就不具体展开介绍了,如需进一步了解,可参考相关资料。

拦截器链


在OkHttp中,责任链中的处理器是各种拦截器,除了自身提供的5个核心拦截器外,它还允许使用者自定义拦截器,并加入其拦截器链链中。先来看看这条“链”的接口定义:

  interface Chain {
    //返回请求对象
    Request request();
    //执行具体的请求,并获取响应
    Response proceed(Request request) throws IOException;
    //返回连接
    Connection connection();
  }

其中proceed的方法很重要,它定义输入请求,输出响应,具体的实现子类来执行。RealInterceptorChain是其实现的子类,其proceed的方法实现如下:

    @Override
    public Response proceed(Request request) throws IOException {
        return proceed(request, streamAllocation, httpCodec, connection);
    }

拦截器链的运行方式

RealInterceptorChain实现的proceed方法调用了自己的proceed的方法,这个方法是拦截器链模式的实现,它定义了我们我们的请求是如何经过层层拦截器处理,获取响应的过程,实现细节参考下面的代码:

    public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
                            RealConnection connection) throws IOException {
        if (index >= interceptors.size()) throw new AssertionError();

        calls++;

        // If we already have a stream, confirm that the incoming request will use it.
        if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
            throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
                    + " must retain the same host and port");
        }

        // If we already have a stream, confirm that this is the only call to chain.proceed().
        if (this.httpCodec != null && calls > 1) {
            throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
                    + " must call proceed() exactly once");
        }

        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(
                interceptors, streamAllocation, httpCodec, connection, index + 1, request);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);

        // Confirm that the next interceptor made its required call to chain.proceed().
        if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
            throw new IllegalStateException("network interceptor " + interceptor
                    + " must call proceed() exactly once");
        }

        // Confirm that the intercepted response isn't null.
        if (response == null) {
            throw new NullPointerException("interceptor " + interceptor + " returned null");
        }
        return response;
    }

从上面的代码中提炼了三句最最核心的代码:

// Call the next interceptor in the chain.
//每次调用取出下一个拦截器,index = index+1就表示下一个拦截器的索引
        RealInterceptorChain next = new RealInterceptorChain(
                interceptors, streamAllocation, httpCodec, connection, index + 1, request);
//取出要处理的拦截器
        Interceptor interceptor = interceptors.get(index);
 //调用每个拦截器的intercept方法,每个拦截器中都要调用chain的proceed方法,这样就是相当于把请求传递到下一个拦截器处理
        Response response = interceptor.intercept(next);

这三句代码实现了请求在不同拦截器间的处理和向下传递。上面代码中有几个关键的参数: interceptors:拦截器集合,所有的拦截器都存储于此集合中; index:拦截器的索引,用于表示当前处理到的拦截器在interceptors列表中的索引位置; 在实现自定义拦截器的时候,一定不要忘了调用的chain的proceed方法,否则链条就要断裂。

“链条”的创建

了解了okhttp中拦截器链的运行方式,来看看这个链条是怎么创建的,以及框架默认创建了哪些拦截器。回到RealCall对象中,请求的发起是通过getResponseWithInterceptorChain实现的,参考代码如下:

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    //添加用户创建的拦截器到拦截器链中,并先于系统默认的拦截器之前执行
    interceptors.addAll(client.interceptors());
    //用于错误恢复和重定向跟踪,创建了后面要使用的StreamAllocation类
    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);
    //通过拦截器执行具体的请求
    return chain.proceed(originalRequest);
  }

此方法中创建了默认的几个核心拦截器,并加入到interceptors集合中,接着创建Chain,并调用了proceed方法,由此开始了请求的处理。

总结


前面分析了okhttp中的拦截器链的创建和运行方式,整个框架的核心部分都在于此。它支撑着这个框架的运行和扩展,大家可细细品味!掌握了这个框架运行的思路,下面我们将会深入分析框架中的几个默认核心拦截器。