OkHttp中的拦截器,顾名思义,拦截网络请求,拦截器系统默认的有几个,大致可以分为两类。其中。Application Interceptors 和Network Interceptors。前者是拦截Client发送的请求,在OkHttp进行处理,接受OkHttp的返回值,后者是拦截OkHttp与Web server的请求,接受服务端返回值。(具体可以看下官方的那张图,看了别人的帖子,很多人都贴上去了,我就不贴了。)
无论哪种Interceptor,都实现了Interceptor这个接口。让我们看看Interceptor这个接口里面代码。简单的不能再简单,说实话,第一眼看到的时候一脸懵逼,懵逼的我做着懵逼的事情。

查看了系统默认的几个Interceptor,也是没看出啥。最后在OkHttpClient这个类里面找文章。果然还找到了,有两个集合分别存放Application Interceptors和Network Interceptors。OkHttpClient在Builder的时候会把已经存在的Interceptor的实例添加到对应的集合中。

之后我们在调用client.newCall(request).execute()的时候,这个newCall里面其实是RealCall这个类去实现的,execute方法里面实际执行的是Response response = getResponseWithInterceptorChain(forWebSocket),看下这个方法里面怎么执行的,重点来了。这个方法里面创造了一个第一张截图接口Chain的实例,然后调用了chain的proceed方法。看下Chain的实例,构造方法前2个参数,一个是index是int类型,一个是request对象,初始化的时候是0和客户端发出的request,后面一个参数先不用管,不影响理解。看下proceed方法,当index的值小于存放拦截器的集合的大小的时候就执行,同时又创建了一个新的实例chain,不过构造的时候把index加了1,同时执行当前对应Interceptor的interceptor方法,看到这里恍然大悟,这不就是递归么。


来来来,知道是这样,我们就可以去代码验证了,用自己写的一个接口试下就,看看怎么拦截的。(苦学这么久的IDEA终于派上用场了,虽然很low,写了两个个简单的jsp和Servlet,服务器端代码就不截图了,看下android端的代码,这个是请求端的代码。)
Activity请求方法:
private void sendRequest() {
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client =new OkHttpClient.Builder()
.addInterceptor(new MyInterceptor())
.addNetworkInterceptor(new MyNetWorkInterceptor())
.build();
Request request =new Request.Builder()
.addHeader("root","root")
.url(HOST.concat("/login.jsp"))
.build();
try {
Response response = client.newCall(request).execute();
String string = response.body().string();
Log.e("responseActivity","============" + string);
}catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
两个Interceptor类代码如下:
public class MyInterceptorimplements Interceptor {
@Override
public Response intercept(Chain chain)throws IOException {
Request request1 = chain.request();
HttpUrl url1 = request1.url();
String httpUrl1 = url1.url().toString();
Headers headers1 = request1.headers();
for (int i =0; i < headers1.size(); i++) {
String name = headers1.name(i);
String value = headers1.get(name);
System.out.print("TAG----------->Name:" + name +"------------>Value:" + value +"\n");
}
Log.e("TAG","httpUrl1============" + httpUrl1);
Request request = chain.request().newBuilder()
.addHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
.addHeader("Accept-Language","zh-CN,zh;q=0.8,en;q=0.6")
.addHeader("Connection","keep-alive")
.url(MainActivity.HOST.concat("/register.jsp"))
.build();
Response response = chain.proceed(request);
int code = response.code();
Log.e("TAG","============response.code========= " + code);
return response;
}
}
public class MyNetWorkInterceptorimplements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain)throws IOException {
Request request1 = chain.request();
HttpUrl url1 = request1.url();
String httpUrl1 = url1.url().toString();
Headers headers1 = request1.headers();
for (int i =0; i < headers1.size(); i++) {
String name = headers1.name(i);
String value = headers1.get(name);
System.out.print("2TAG----------->Name:" + name +"------------>2Value:" + value +"\n");
}
Log.e("2TAG","httpUrl============" + httpUrl1);
Request request = chain.request().newBuilder()
.url(MainActivity.HOST.concat("/register.jsp"))
.build();
Response response = chain.proceed(request);
int code = response.code();
Log.e("2TAG","============response.code========= " + code);
return response;
}
}

上图是运行后的Log截图,可以看到最初的请求链接是Host:login.jsp,请求头只有一个root在第一个拦截器中我设置了重定向,重新发送请求,在第二个拦截器中拦截到了这些设置,可以看2TAG后面的请求头信息,而且url变成了HOST:register.jsp,两个返回先返回给了网络拦截器,后返回给了应用拦截器。最后把respose的body返回值给了activity里面调用的地方。
回头总结下,虽然OkHttp现在用的比较少了,Retrofit用的比较多。其实流行的Retrofit也是建立在Okhttp的基础上面的,OkHttp的拦截器思想挺有意思的,还有拦截器的分层思想,留待以后慢慢领悟吧。
网友评论