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

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

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

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

看下面这张图:

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

看下图:

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

技术共享笔记

©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页