美文网首页Android开发经验谈Android文章Android开发
Android小知识-介绍OkHttp中的拦截器

Android小知识-介绍OkHttp中的拦截器

作者: 爱读书的顾先生 | 来源:发表于2018-10-25 08:21 被阅读1440次

    本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众号,谢谢

    在OkHttp中执行同步请求会阻塞当前线程,直到HTTP响应返回,同步请求使用的是execute()方法;而异步请求类似于非阻塞式的请求,它的执行结果一般通过接口回调的方式告知调用者,异步请求使用的是enqueue(Callback)方法;

    OkHttp中不管是同步还是异步,都是通过拦截器完成网络的获取。

    官网对拦截器的解释是:拦截器是OkHttp中提供的一种强大机制,它可以实现网络监听、请求以及响应重写、请求失败重试等功能。

    看下面这张图:

    image

    在这张图中可以看到有两种拦截器,一种是APPLICATION INTERCEPTORS,也就是应用拦截器;第二种是NETWORK INTERCEPTORS,表示网络拦截器。除了这两种拦截器,重要的是中间OkHttp core这块,这是OkHttp提供的内部拦截器。

    看下图:

    image

    这是OkHttp提供给我们的拦截器,内部是以拦截器的链的形式执行HTTP的请求,其中RetryAndFollowUpInterceptor是重试和失败重定向拦截器,BridgeInterceptor是桥接和适配拦截器,CacheInterceptor是缓存拦截器,ConnectInterceptor是连接拦截器,负责建立可用的连接,CallServerInterceptor负责将HTTP的请求写入网络的IO流中,并且从网络IO流中读取服务端返回给客户端的数据。

    看过前面几节的同学应该知道,无论是同步请求还是异步请求,最终执行网络请求并获取的Response都是通过getResponseWithInterceptorChain()方法获取的,代码如下。

          //异步请求
        @Override protected void execute() {
            boolean signalledCallback = false;
            try {
                //重点1 使用拦截器链
                Response response = getResponseWithInterceptorChain();
                ...
            } catch (IOException e) {
                ...
            } finally {
                回收请求
                client.dispatcher().finished(this);
            }
        }
    
        //同步请求
        @Override public Response execute() throws IOException {
            //第一步:判断同一Http是否请求过
            ...
            //捕捉Http请求的异常堆栈信息
            ...
            //监听请求开始
            ...
            try {
                //第二步:同步请求添加到同步队列中
                ...
                //第三步:使用拦截器链
                Response result = getResponseWithInterceptorChain();
                ...
            } catch (IOException e) {
                ...
            } finally {
                //第四步:回收请求
                client.dispatcher().finished(this);
            }
        }
    

    getResponseWithInterceptorChain()方法返回的就是我们网络请求的响应结果Response对象。

    进入getResponseWithInterceptorChain()方法:

      Response getResponseWithInterceptorChain() throws IOException {
            // Build a full stack of interceptors.
            List<Interceptor> interceptors = new ArrayList<>();
            //用户自定义的拦截器
            interceptors.addAll(client.interceptors());
            //添加OkHttp提供的五个拦截器以及networkInterceptors
            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));
            //标记1
            Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
                    originalRequest, this, eventListener, client.connectTimeoutMillis(),
                    client.readTimeoutMillis(), client.writeTimeoutMillis());
            //标记2
            return chain.proceed(originalRequest);
        }
    

    getResponseWithInterceptorChain方法一开始将我们需要的拦截器添加到一个集合中,其中就包括我们自定义的拦截器以及上面提到的几种拦截器。

    接着在标记1处创建了一个RealInterceptorChain对象,传入的第一个参数就是上面的添加的一系列拦截器,创建完毕后,在标记2处执行RealInterceptorChain对象的proceed方法。

    进入RealInterceptorChain的proceed方法:

     @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 {
            ...
            //标记1
            RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
                    connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
                    writeTimeout);
            //标记2:取出index位置的拦截器
            Interceptor interceptor = interceptors.get(index);
            //标记3
            Response response = interceptor.intercept(next);
    
            ...
            return response;
        }
    

    在标记1处又创建了一个RealInterceptorChain对象,在创建对象时,传入的第五个参数是index+1,这样的话在下次访问时,只能从下一个拦截器开始进行访问,而不能从当前拦截器。

    在标记2处取出第index位置的拦截器。

    在标记3处将代表下一个拦截器的链的RealInterceptorChain对象传入当前位置的拦截器中,在当前拦截器链中执行请求,获取Response后依次返回给它的上一个拦截器,如果当前拦截器没有获取Response就继续调用RealInterceptorChain对象的prceed方法来创建下一个拦截器链,就这样拦截器链一层一层的调用,这样所有的拦截器链构成了一个完整的链条。

    到目前为止,总结如下:

    1. 创建一系列拦截器,并将其放入一个拦截器list集合中。

    2. 创建一个拦截器链RealInterceptorChain,并执行拦截器链的proceed方法,这个proceed方法的核心是继续创建下一个拦截器链。

    我们看下RetryAndFollowUpInterceptor这个拦截器,它是重试和失败重定向拦截器。

        @Override public Response intercept(Interceptor.Chain chain) throws IOException {
            ...
            RealInterceptorChain realChain = (RealInterceptorChain) chain;
            ...
            response = realChain.proceed(request, streamAllocation, null, null);
            ...
        }
    

    可以看到RetryAndFollowUpInterceptor拦截器的intercept方法,内部又执行了传递进来的RealInterceptorChain对象的proceed方法,而proceed方法在上面介绍过了,作用是创建下一个拦截器链,这样就说明了整个拦截器链的执行过程就像链条一样,一环扣一环。


    838794-506ddad529df4cd4.webp.jpg

    搜索微信“顾林海”公众号,定期推送优质文章。

    相关文章

      网友评论

        本文标题:Android小知识-介绍OkHttp中的拦截器

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