OkHttp3 拦截器

Android OkHttp拦截器源码分析二--两种自定义拦截器

2018-10-08  本文已影响32人  青果果

上面一篇文章简单介绍了拦截器,源码中拦截器的种类及作用,以及自定义拦截器和注册自定义拦截器

上篇已经讲了源码中拦截器的执行顺序
这篇主要从源码角度分析

okhttp GitHub关于拦截器的介绍
链接:https://github.com/square/okhttp/wiki/Interceptors
如果你有看这个链接,或看其他人的文章肯定很疑惑为啥
会说NetworkInterceptor走两次
因为他们都没说详细的原因,来别急,看了下面的例子就会清楚了

Interceptor 实例看结果

可以先忽略小标题看代码就好
下面分别是自定义的两种拦截器,应用拦截器和网络拦截器,来测试一下看结果

public class AppInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Log.e("Interceptor", "app intercept:begin ");
        Request request = chain.request();
        Response response = chain.proceed(request);//请求
        Log.e("Interceptor", "app intercept:end; " + request.url()+", response ," +
                response.request().url()+" code: " + response.code());
        return response;
    }
}
public class NetworkInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Log.e("Interceptor","network interceptor:begin");
        Request request = chain.request();
        Response  response = chain.proceed(request);//请求
        Log.e("Interceptor","network interceptor:end;" + request.url()+", response ," +
                response.request().url()+" code: " + response.code());
        return response;
    }
}

发起网络请求

OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .addInterceptor(new AppInterceptor())
                .addNetworkInterceptor(new NetworkInterceptor())
                .build();

 Request request = new Request.Builder().url("http://www.baidu.com/").build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                LogUtils.d("Interceptor", "--" + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                LogUtils.d("Interceptor", "--" + response.toString());
            }
        });

没有发生重定向结果

10-08 01:04:24.435 20080-20301/com.qgg.practice E/Interceptor: app intercept:begin 
10-08 01:04:24.477 20080-20301/com.qgg.practice E/Interceptor: network interceptor:begin
10-08 01:04:24.494 20080-20301/com.qgg.practice E/Interceptor: network interceptor:end;http://www.baidu.com/, response ,http://www.baidu.com/ code: 200
10-08 01:04:24.496 20080-20301/com.qgg.practice E/Interceptor: app intercept:end; http://www.baidu.com/, response ,http://www.baidu.com/ code: 200
10-08 01:04:24.497 20080-20301/com.qgg.practice D/Interceptor: --Response{protocol=http/1.1, code=200, message=OK, url=http://www.baidu.com/}

发生重定向结果

如果你把上面的地址改为 http://www.baidu.cn

 Request request = new Request.Builder().url("http://www.baidu.cn").build();
10-08 00:56:59.149 19078-19142/com.qgg.practice E/Interceptor: app intercept:begin 
10-08 00:56:59.181 19078-19142/com.qgg.practice E/Interceptor: network interceptor:begin
10-08 00:56:59.198 19078-19142/com.qgg.practice E/Interceptor: network interceptor:end;http://www.baidu.cn/, response ,http://www.baidu.cn/ code: 302
10-08 00:56:59.212 19078-19142/com.qgg.practice E/Interceptor: network interceptor:begin
10-08 00:56:59.222 19078-19142/com.qgg.practice E/Interceptor: network interceptor:end;http://www.baidu.com/, response ,http://www.baidu.com/ code: 200
10-08 00:56:59.225 19078-19142/com.qgg.practice E/Interceptor: app intercept:end; http://www.baidu.cn/, response ,http://www.baidu.com/ code: 200
10-08 00:56:59.225 19078-19142/com.qgg.practice D/Interceptor: --Response{protocol=http/1.1, code=200, message=OK, url=http://www.baidu.com/}

咦,确实,网络拦截器竟然走了两次
其实标题已经说明了原因,对,就是因为发生了重定向,可以看到之前有返回httpcode 302
这时第一类拦截器就起了作用 RetryAndFollowUpInterceptor 帮我们访问了http://www.baidu.com/

RetryAndFollowUpInterceptor 详细分析的时候再来说明

现在就可以把官网的两种拦截器的详细对比贴出来了
Application and Network interceptors 该如何选择

两个interceptor都有他们各自的优缺点:

Application Interceptors

Network Interceptors

结合图和例子,再看上面的两种区别分析应该理解的比较清楚了

Interceptor 源码分析

可以看到源码设计的很巧妙 Interceptor 是接口
所以,可以肯定的是之前介绍的源码中的五种拦截器都是实现了Interceptor 接口
Interceptor 中只有一个方法intercept 参数为Chain,返回值为Response
而Chain又是一个接口

/**
 * Observes, modifies, and potentially short-circuits requests going out and the corresponding
 * responses coming back in. Typically interceptors add, remove, or transform headers on the request
 * or response.
 */
public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    /**
     * Returns the connection the request will be executed on. This is only available in the chains
     * of network interceptors; for application interceptors this is always null.
     */
    @Nullable Connection connection();

    Call call();

    int connectTimeoutMillis();

    Chain withConnectTimeout(int timeout, TimeUnit unit);

    int readTimeoutMillis();

    Chain withReadTimeout(int timeout, TimeUnit unit);

    int writeTimeoutMillis();

    Chain withWriteTimeout(int timeout, TimeUnit unit);
  }
}

未完待续...

上一篇 下一篇

猜你喜欢

热点阅读