okhttp之拦截器

拦截器的实现使用了责任链模式,了解一下责任链模式对理解起来有帮助。

本文注意分析拦截器的“链”如何形成、开始和结束。

1. 介绍

拦截器,可以拦截请求和响应,对数据进行监视或者修改。拦截器使用双链责任链,先添加的拦截器最先拦截请求,最后拦截响应。拦截器分为网络拦截器和应用拦截器,一般添加的都是应用拦截器。

2. 使用

  1. 添加依赖
api 'com.squareup.okhttp3:okhttp:3.14.9'

4.0及以上内部实现为kotlin,这里分析3.14.9版本,不同版本源码会有差异。

  1. 自定义拦截器
/**
 * Copyright © www.zingking.cn
 *
 * 自定义拦截器
 */
class CustomInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        // deal request ...
        val response = chain.proceed(chain.request())
        // deal response ...
        return response
    }
}
  1. 创建请求
// 示例类
class xx{
    // 实例方法
    fun request(){
        val url = "http://www.baidu.com"
        val okHttpClient = OkHttpClient().newBuilder()
                                // 添加拦截器
                                .addInterceptor(CustomInterceptor())
                                .build()
        val request: Request = Request.Builder()
                                .url(url)
                                .build()
        val call: Call = okHttpClient.newCall(request)
        // 同步请求
        var response: Response = call.execute()
        // 或者异步请求
        call.enqueue(object :Callback{
            override fun onFailure(call: Call, e: IOException) {

            }

            override fun onResponse(call: Call, response: Response) {

            }
        })
    }
}

3. 分析

基于com.squareup.okhttp3:okhttp:3.14.9

根据前面的介绍,思考几个问题:

  1. okhttp内部有没有默认拦截器?有什么作用?
  2. 自定义添加的拦截器和内部拦截器的优先级如何?
  3. 如何替换okhttp内部网络请求?

3.1 拦截器的相关类

拦截器涉及到的相关类不仅仅是为拦截器服务,这里只会着重介绍和拦截器相关的代码。

看一下类图:

Interceptor.png

类图展示了与拦截器相关的关键关系,其余关系再加上去会很混乱,例如:RealInterceptorChain实际上持有Request和Call成员变量,与其2个是关联关系。第一行是网络请求参数和结果,第二行是执行的请求、拦截器、“链”接口,第三行是接口的实现类和OkHttpClient。

Request

“链”中持有的请求参数,也是责任链模式双链中的第1条链,拦截请求的关键参数。

Response

“链”中处理后的响应参数,也是责任链模式双链中的第2条链,拦截响应的关键参数。

Call和RealCall

一个Call是一个已准备执行的请求,内部有同步执行和异步执行。 而RealCall是Call接口的唯一(final)实现类,内部持有了OkHttpClientRequest,也是责任链开始的地方。

Interceptor

拦截器接口,内部只有一个拦截方法,其实现类是属于链中的某一个具体的处理对象;自定义拦截器实现该方法可以处理请求参数和响应结果。

Chain和RealInterceptorChain

“链”接口,是Interceptor内部类接口,内部有比较多的接口方法,这里只关心和拦截器相关的。“链”用来串联起具体的处理对象并携带有请求参数,管理调用顺序。在责任链模式中,一般处理方法和传递方法都是同一个(例如:handleRequest)。拦截器的实现把这两个方法分开了,处理方法是Interceptor.intercept(...),传递方法是Interceptor.Chain.proceed(...)

RealInterceptorChain是Chain接口的唯一(final)实现类,内部持有所有的拦截器集合,和当前链应该处理的拦截器索引。在实际传递和拦截过程中也创建的该对象。

OkHttpClient

okhttp的客户端类,功能很多,这里只关心和拦截器相关的。内部维护了2个拦截器集合,一个是普通拦截器,一个是网络拦截器。2个集合会在请求时被添加到RealInterceptorChain中的集合里一起传递。

3.2 源码

RequestResponse在拦截器中作为链传递时携带的数据,内部源码都是一些请求参数和响应结果,这里不会再分析源码。

  • Chain是Interceptor的内部类接口,Chain目前只有一个唯一的实现类RealInterceptorChain且是final的,来看一下这三个的源码:
// 抽象的处理者,其实现类是属于链中的某一个具体的处理对象
public interface Interceptor {

    // 处理方法,由具体处理者实现该方法,处理自己对应的业务逻辑
    Response intercept(Chain chain) throws IOException;

    interface Chain {
        // 得到链中传递的请求参数
        Request request();

        // 传递方法,将请求传递给下一个处理对象
        Response proceed(Request request) throws IOException;

        // 返回请求将被执行的连接。 这个方法仅在网络拦截器中使用,音乐拦截器返回永远是空
        @Nullable Connection connection();
        ...
    }
}

Interceptor是拦截器,自定义的拦截器中实现intercept方法,可以拿到“链”对象并对其请求进行处理,接着可以调用“链”对象的proceed方法,将请求传递到下一个拦截器。如果不调用proceed方法,后面的拦截器也就不会再处理。这样一直传递到最后一个拦截器,返回Response实例。接着看一下拦截链的源码:

// 承载整个拦截链的具体拦截链 
public final class RealInterceptorChain implements Interceptor.Chain {
    // 所有拦截器集合,包含内部默认和自定义添加的
    private final List interceptors;
    // 当前链中对应的拦截器索引
    private final int index;
    // 网络请求参数,但是在链传递过程中的请求参数不是这个
    private final Request request;
    // 构造函数,给成员变量赋值
    public RealInterceptorChain(List interceptors, Transmitter transmitter,
                                @Nullable Exchange exchange, int index, Request request, Call call,
                                int connectTimeout, int readTimeout, int writeTimeout) {
        this.xx = xx;
    }
    // 实现接口方法,返回网络请求
    @Override
    public Request request() {
        return request;
    }
    // 实现接口方法
    @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 {
        // 省略一些参数校验...
        // 调用链中的下一个拦截器
        
        // RealInterceptorChain 第 1 4 5 个参数分别为:
        // interceptors:包含所有拦截器的集合;index + 1:下一个链中对应的拦截器索引;request:请求参数
        // 注意:request是局部变量,即入参的requset,不是成员变量;保证了每次拦截对request的修改都有效
        RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
                                                    index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
        // 获取当前链对应的拦截器
        Interceptor interceptor = interceptors.get(index);
        // 调用当前链的拦截方法,注意参数是下一个链,可以理解为在下一个链之前拦截
        Response response = interceptor.intercept(next);
        // 省略一些合法性校验...
        return response;
    }
}

关键方法proceed(...),创建了一个新的RealInterceptorChain实例作为下一个拦截链,并调用当前拦截器的拦截方法;例如当index为0时,当前链实例的所有成员变量(request等)都是"0版本",故新的RealInterceptorChain实例持有的成员变量在调用interceptor.intercept(next)之前都是“0版本”,只有索引指向了下一个拦截器;在实现interceptor时,可以对链实例的成员变量进行操作,而操作后的成员变量可以理解为“1版本”,此时index(等于1)和成员变量版本一一对应。

即“0版本成员变量”和“1索引”作为参数封装到一起传递给第0个拦截器处理,在第0个拦截器处理后“0版本成员变量”发生了变化即与“1索引”一一对应了。

  • OkHttpClient在拦截器中的作用就比较简单,维护了2个拦截器集合用于暂存自定义的拦截器,请求开始时会被整体添加到RealInterceptorChain中的集合里:
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
    // 应用拦截器
    final List interceptors;
    // 网络拦截器
    final List networkInterceptors;
    // 返回应用拦截器
    public List interceptors() {
        return interceptors;
    }
    // 返回网络拦截器
    public List networkInterceptors() {
        return networkInterceptors;
    }
    
    // 接收一个请求参数,创建一个Call
    @Override 
    public Call newCall(Request request) {
        // 调用RealCall静态方法,第三个参数为false
        return RealCall.newRealCall(this, request, false);
    }
    
    // 通过builder链式调用创建OkHttpClient实例
    public static final class Builder{
        ...
    }
}
  • Call和RealCall,RealCall作为Call的实现类,是请求的开始固然也是拦截器开始:
public interface Call extends Cloneable {
    // 返回发起此调用的原始请求。 
    Request request();

    // 同步执行请求
    Response execute() throws IOException;

    // 异步执行请求
    void enqueue(Callback responseCallback);
}
final class RealCall implements Call {
    // OkHttpClient实例
    final OkHttpClient client;
    // 原始请求
    final Request originalRequest;
    // 是否是针对webSocket
    final boolean forWebSocket;

    // 构造函数给成员变量赋值
    private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        this.client = client;
        this.originalRequest = originalRequest;
        this.forWebSocket = forWebSocket;
    }

    // 静态方法创建Call
    static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        // Safely publish the Call instance to the EventListener.
        RealCall call = new RealCall(client, originalRequest, forWebSocket);
        call.transmitter = new Transmitter(client, call);
        return call;
    }

    // 返回原始请求
    @Override public Request request() {
        return originalRequest;
    }
    // 同步执行
    @Override public Response execute() throws IOException {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        transmitter.timeoutEnter();
        transmitter.callStart();
        try {
            client.dispatcher().executed(this);
            // * 调用内部方法获取响应结果
            return getResponseWithInterceptorChain();
        } finally {
            client.dispatcher().finished(this);
        }
    }

    // 异步执行
    @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        transmitter.callStart();
        // 将回调添加到一个runnable中
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }
    
    // 异步执行的Runnable
    final class AsyncCall extends NamedRunnable {
        
        AsyncCall(Callback responseCallback) {
            super("OkHttp %s", redactedUrl());
            this.responseCallback = responseCallback;
        }
        
        // 异步执行时会调度到这里
        @Override
        protected void execute() {
            boolean signalledCallback = false;
            transmitter.timeoutEnter();
            try {
                // * 调用内部方法获取响应结果
                Response response = getResponseWithInterceptorChain();
                signalledCallback = true;
                responseCallback.onResponse(RealCall.this, response);
            } catch (IOException e) {
                if (signalledCallback) {
                    Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
                } else {
                    responseCallback.onFailure(RealCall.this, e);
                }
            } catch (Throwable t) {
                cancel();
                if (!signalledCallback) {
                    IOException canceledException = new IOException("canceled due to " + t);
                    canceledException.addSuppressed(t);
                    responseCallback.onFailure(RealCall.this, canceledException);
                }
                throw t;
            } finally {
                client.dispatcher().finished(this);
            }
        }
    }
}

通过上面的分析可以看出,无论是同步还是异步,最后都会执行到getResponseWithInterceptorChain()这个方法来获取响应结果:

final class RealCall implements Call {
    // 获取响应结果
    Response getResponseWithInterceptorChain() throws IOException {
        // 构建一个完整的拦截器列表,即包含了内部默认和自定义
        List interceptors = new ArrayList<>();
        // 添加client携带的应用拦截件集合
        interceptors.addAll(client.interceptors());
        // 添加4个内部默认的拦截器
        interceptors.add(new RetryAndFollowUpInterceptor(client));
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        interceptors.add(new CacheInterceptor(client.internalCache()));
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
            // 添加client携带的网络拦截件集合
            interceptors.addAll(client.networkInterceptors());
        }
        // 添加最后一个调用网络服务的拦截器,最终的网络请求就是在这里
        interceptors.add(new CallServerInterceptor(forWebSocket));
        // 创建第1个拦截链,重要参数包含:所有拦截器interceptors;索引 0 ;请求参数originalRequest;
        Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
                                                           originalRequest, this, client.connectTimeoutMillis(),
                                                           client.readTimeoutMillis(), client.writeTimeoutMillis());

        boolean calledNoMoreExchanges = false;
        try {
            // 开始执行第0个拦截链;注意这里不是interceptor.intercept(chain);
            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);
            }
        }
    }
}

通过上面的分析很容易了解:

  • 内部有5个拦截器
  • 自定义应用拦截器优先级最高;发生网络请求的拦截器优先级最低,自定义网络拦截器次之;中间是默认的一些配置、功能性拦截器
  • 若在自定义拦截器中直接返回结果,而不是调用chain.proceed(...)即可替换内部网络请求

4. 总结

  • 拦截器使用责任链双链模式
  • 自定义应用拦截器优先级最高
  • 先添加的拦截器最先拦截请求,最后拦截结果(责任链的特性)

你可能感兴趣的:(okhttp之拦截器)