美文网首页
Okhttp源码学习(调用流程、拦截器原理)

Okhttp源码学习(调用流程、拦截器原理)

作者: 浪里_个郎 | 来源:发表于2020-06-10 18:30 被阅读0次
    OKHTTP调用流程

    execute()是同步请求,enqueue(Callback)是同步请求。
    Dispatcher 内部维护着三个队列:同步请求队列 runningSyncCalls、异步请求队列 runningAsyncCalls、异步缓存队列 readyAsyncCalls,和一个线程池 executorService。

    OkHttp对于网络请求都有哪些优化:

    a、通过连接池来减少请求延时
    b、无缝支持GZIP来减少数据流量
    c、缓存响应数据来减少重复的网络请求
    d、可以从很多常用的连接问题中自动恢复

    拦截器

    使用示例

    OKHttp中使用OKHttpClient将request转为Call网络访问对象。OkHttpClient还具备addInterceptor()方法添加拦截器,我们可以自己实现接口,用于对Http请求进行设置,以及对Response进行预处理。
    拦截器的意义在于我们可以将一些重复性的代码提取出来供不同的网络请求复用。
    比如我们可以用OKHttp写这样一个完整的请求:

    //异步get请求:
    OkHttpClient okHttpClient = new OkHttpClient();
    final Request request = new Request.Builder()
            .url(url)
            .get()//默认就是GET请求,可以不写
            .build();
    //通过Builder设置请求参数
    sOkHttpClient = new OkHttpClient.Builder()
            .connectTimeout(DEFAULT_TIMEOUT_CONNECT, TimeUnit.SECONDS)
            .readTimeout(DEFAULT_TIMEOUT_READ, TimeUnit.SECONDS)
            .writeTimeout(DEFAULT_TIMEOUT_WRITE, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .cache(new Cache(new File(AppApplication.getInstance()
                    .getCacheDir(),""),1024*1024*10))
             //添加拦截器
            .addInterceptor(InterceptorUtil.getHeadInterceptor())
            .addInterceptor(InterceptorUtil.getLogInterceptor())
            .addInterceptor(InterceptorUtil.getCacheInterceptor())
            .addNetworkInterceptor(InterceptorUtil.getCacheInterceptor())
            .build();
    Call call = sOkHttpClient.newCall(request);
    Response response = call.execute();
    

    拦截器接口实现示例如下:

        /**
         * 返回匿名头部拦截器
         * @return
         */
        public static Interceptor getHeadInterceptor(){
            return new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    //处理业务逻辑,可以对header统一处理,涉及到header加密的也在此处理
                    //在这里可以做一些想做的事,比如token失效时,重新获取token
                    //或者添加header等等
                    Request build = chain.request().newBuilder()
                            .addHeader("Content-Type", "application/json")
                            .build();
                    return chain.proceed(build);
                }
            };
        }
    

    所有添加的拦截器,都存储在OKHttpClient的List成员变量中。Call的实现类和InterceptorChain实现类会获得这个拦截器容器。


    类图:拦截器容器在三个类中使用

    下面看看拦截器是如何被拦截链(InterceptorChain)使用的。


    Call的executed方法中通过拦截链使用拦截器

    client.newCall(request)中传入的request会被封装进RealCall类型。红色方框中这行代码,它并没有真正的执行网络请求,而只是简单地将请求放入请求池中,让它等待分派器的后续执行。而真正的执行体在上面的蓝色方框中,它封装了一个拦截器链(Chain),并调用了Chain的procced方法,传入原始的request对象,这里开始拦截器链的调用过程:

    拦截链调用流程

    在拦截器的proceed方法中,会遍历存储所有拦截器的容器,它使用循环+递归的方式,将拦截器串联起来。Request和response都存储于Chain中,供每一层拦截器修改:

    拦截器对request和response的拦截

    应用拦截器和网络拦截器拦截器


    差别在于,Application Interceptor,即普通的自定义Interceptor,接收到的response是经过OKHttp core处理过的(比如经过了封装),而NetWork Interceptor是服务器返回的原始response

    Interceptor的责任链模式

    OkHttp使用了责任链模式来实现拦截器的调用特性。责任链,我将其理解为一颗只有左节点的树。

    责任链模式的类DFS调用方式

    拦截器的调用过程,就类似于对这棵树进行递归方式的DFS遍历:

    责任链模式 (1).png

    所以排在前面的拦截器会首先被执行,而Response最后才返回。

    相关文章

      网友评论

          本文标题:Okhttp源码学习(调用流程、拦截器原理)

          本文链接:https://www.haomeiwen.com/subject/ddkutktx.html