OkHttp拦截器链源码解读

同步异步源码解读的传送门https://www.jianshu.com/p/baf47f6f0e11
OkHttp网络请求的重中之重拦截器链,在官方文档中是这样解释的:
拦截器是OkHttp中提供的一种强大机制,它可以实现网络监听、请求以及响应重写、请求失败重试等功能。

PS:拦截器是不区分同步和异步的
下面这是官网的图:

image.png

一种是系统应用的拦截器,一种是网络拦截器,这里我们只谈OkHttp内部系统的拦截器,总共分为5种。如下图所示:


image.png

我们再回到RealCall这个类中,看看同步和异步最终执行的方法:
同步:

@Override public Response execute() throws IOException {
        synchronized (this) { // 加同步锁
            // 同一个http请求只能执行一次,执行完就设置为你true
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        captureCallStackTrace();
        timeout.enter();
        eventListener.callStart(this);
        try {
            client.dispatcher().executed(this);
            Response result = getResponseWithInterceptorChain();
            if (result == null) throw new IOException("Canceled");
            return result;
        } catch (IOException e) {
            e = timeoutExit(e);
            eventListener.callFailed(this, e);
            throw e;
        } finally {
            client.dispatcher().finished(this);
        }
    }

异步:

@Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
            // 和同步一样判断是否请求过这个链接,已经请求过就直接抛出异常
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true; // 请求过就设置为true
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback)); // 关键代码
    }

异步线程真实执行的方法:
// 这个方法才是线程真正实现的方法,在父类NamedRunnable中是一个抽象的方法,在线程的run方法中实现的
        @Override protected void execute() { // 这个方法是在子线程中操作的
            boolean signalledCallback = false;
            timeout.enter();
            try {
                Response response = getResponseWithInterceptorChain(); // 拦截器链
                if (retryAndFollowUpInterceptor.isCanceled()) { // 重定向和重试的拦截器是否取消了
                    signalledCallback = true;
                    // 如果取消了,就回掉返回失败给用户
                    responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
                } else {
                    signalledCallback = true;
                    // 没取消重定向拦截器就正常返回数据
                    responseCallback.onResponse(RealCall.this, response);
                }
            } catch (IOException e) {
                e = timeoutExit(e);
                if (signalledCallback) {
                    // Do not signal the callback twice!
                    Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
                } else {
                    eventListener.callFailed(RealCall.this, e);
                    responseCallback.onFailure(RealCall.this, e);
                }
            } finally {
                /**
                 * 这个finish做的事情
                 * 1.把这个请求从正在请求的队列中删除
                 * 2.调整我们整个异步请求的队列,因为这个队列是非线程安全的
                 * 3.重新调整异步请求的数量
                 */
                client.dispatcher().finished(this);
            }
        }
    }

从上面看出,不管是同步还是异步都使用了拦截器链,返回Response 对象

下面我们来看看getResponseWithInterceptorChain()这个方法:

// 所使用的拦截器链 在官网上分为两个拦截器 Application 应用拦截器和NetWork网络拦截器
    Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List 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); // 拦截后调用proceed方法来执行相应请求
    }

从代码中可以看出,是一个List集合依次添加用户自定义的拦截器和OkHttp内部的一系列拦截器,到最后通过RealInterceptorChain对象创建出一个拦截器链Interceptor.Chain来,拦截器链执行chain.proceed方法。我们跟着这个方法走进去到RealInterceptorChain类中,对应的方法:

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

最终到这个方法中:
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. 核心方法实现 就是创建下一个拦截器链
        /**
         * 创建了一个拦截器的链,这个链和刚才前面讲的链的区别 ,传入的参数是index + 1,意思就是如果我们下面
         * 要访问的话,只能从下一个拦截器访问,不能从当前拦截器访问,这就形成了一个拦截器链
         */
        RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
                connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
                writeTimeout);
        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");
        }

        if (response.body() == null) {
            throw new IllegalStateException(
                    "interceptor " + interceptor + " returned a response with no body");
        }

        return response;
    }

这里面的核心在上面代码中已经写明,这里就不在阐述了。
所有的拦截器都实现了Interceptor这个接口:

/**
 * 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;

    // 也就是说我们可以通过实现Interceptor,定义一个拦截器对象,然后拿到请求和Response对象,对Request和Response进行修改
    interface Chain {
        // 实现chain接口对象的request方法可以拿到Request对象
        okhttp3.Request request();

        // 实现chain接口对象的proceed方法可以拿到Response对象
        Response proceed(Request request) throws IOException;

        /**
         * Returns the connection the request will be executed on. This is only available in the chains
         * of network interceptors; for application interceptors this is always null.
         *
         * 返回将在其上执行请求的连接。这只适用于链条对于网络拦截器;对于应用程序拦截器,此值始终为空
         */
        @Nullable
        Connection connection();

        Call call();

        int connectTimeoutMillis();

        Chain withConnectTimeout(int timeout, TimeUnit unit);

        int readTimeoutMillis();

        Chain withReadTimeout(int timeout, TimeUnit unit);

        int writeTimeoutMillis();

        Chain withWriteTimeout(int timeout, TimeUnit unit);
    }
}

其实整个OkHttpde 请求就是经过这一个个的拦截器链的chain.proceed方法完成的。

我们来简单做个总结:
1.创建一系列拦截器,并将其放入一个拦截器list中。
2.创建一个拦截器链RealInterceptorChain,并执行拦截器链的proceed方法。
3.在发起请求前对request进行处理。
4.调用下一个拦截器,获取Response。
5.对Response进行处理,返回给上一个拦截器。
我们这里完全可以自定义拦截器,实现Interceptor,生成一个拦截器对象,然后拿到请求Request对象和响应Response对象,对Request和Response进行修改。

整个流程就是OkHttp通过定义许多拦截器一步一步地对Request进行拦截处理(从头至尾),直到请求返回网络数据,后面又倒过来,一步一步地对Response进行拦截处理,最后拦截的结果就是回调给调用者的最终Response。(从尾至头)
上一张图很清晰的理清拦截器的操作:


image.png

这篇先到这里,下一篇我们把OkHttp中的这5个拦截器一一细细分析。
感谢观看,如有错误,欢迎指正。

OkHttp的重定向及重试拦截器的源码解读:https://www.jianshu.com/p/d70f07288afc

你可能感兴趣的:(OkHttp拦截器链源码解读)