为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
Android

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

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

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

看下面这张图:

webp

image

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

看下图:

webp

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方法在上面介绍过了,作用是创建下一个拦截器链,这样就说明了整个拦截器链的执行过程就像链条一样,一环扣一



作者:顾林海
链接:https://www.jianshu.com/p/084b4d4ede11


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消