本篇主要讲述那interceptors里面的5种interceptor
以及自定义一个interceptor的一些注意事项.
相关OkHttp的其他内容,请看前两篇.
上篇:https://blog.csdn.net/heming9174/article/details/88379018
中篇:https://blog.csdn.net/heming9174/article/details/88381797
所有interceptor进来直接看intercept().
而且分为3个部分去看.
分别是:proceed()前置的逻辑,proceed()分割线,proceed()后置的逻辑.
RetryAndFollowUpInterceptor
-
proceed()前置逻辑
这个interceptor其实没有做什么前置处理.
只是创建一个包含3个OKHTTP关键内容的StreamAllocation.
分别是Connections(客户端和服务端之间的连接)、Streams(向服务器发送消息和接受服务器传递的消息的这2个动作)、Calls(发起请求,获得Response).同时还需要注意一下,整个retryAndFollowUp的逻辑是包含在一个while(true){}的死循环内.
-
proceed()
跳转到RealInterceptorChain.proceed()创建指向CacheInterceptor的Chain和从interceptors获取BridgeInterceptor. -
proceed()后置逻辑
整个后置逻辑里面,最核心的就是
followUp = followUpRequest(response, streamAllocation.route());
看看他做了什么?
将执行完一个完整interceptor链传递回来的response传递了进去.
返回了一个Request.
拿着前面的部分代码举栗子.
获取响应码,直接switch/case.比如30X…各种重定向(地址临时性迁移重定向,地址永久性迁移重定向)(注意!没有包含304:内容没有改变直接获取缓存,这个应该是在CacheInterceptor处理).
这个后置逻辑说白了就是 判断响应码,如果是超时(retry),重定向(followUp,获取Location内的url),重新包装一个Request,直接重新去请求,(注意是在一个while(true){}的死循环里面)直至获取到的Response不包含这些响应码,也就是followUp为空,直接return response; 跳出这个死循环.
BridgeInterceptor
-
proceed()前置逻辑
这里处理的内容挺多.
因为请求跳转到这里以后,body的内容已经确定了,然后根据body来添加head的各种属性.
比如说:Content-Type、判断body大小来添加固定大小还是不确定大小分段下载的’chunked’、User-Agent、从CookieJar内获取缓存啥的巴拉巴拉…值得注意的是:如果我们没有添加"Accept-Encoding",会给我们默认添加一个"gzip",表示我们可以默认接受服务器传递过来的gzip格式的数据,OKHTTP会帮我们进行解析.
为什么会刻意提到这个呢?因为这个关系到自定义的interceptor或者networkInterceptor,如果自定义的是networkInterceptor,如果服务器传递的是gzip,没有经过BridgeInterceptor的后置逻辑去解析gzip的数据,你会发现获取到的Response.body无法正常使用. -
proceed()
跳转到RealInterceptorChain.proceed()创建指向ConnectInterceptor的Chain和从interceptors获取CacheInterceptor. -
proceed()后置逻辑
后置逻辑主要做了2个事情.分别是
1.保存Cookie到CookieJar,注意那个保存的方法,想起来了没有?就是我们在上篇讲解OkHttpClient里面,可以自己随便定义实现的CookieJar接口,自定义保存和获取Cookie的方法.
2.解析gzip数据.毕竟在前置逻辑里面,如果没有添加"Accept-Encoding",OKHTTP可是默认给你添加了一个我支持服务器传递过来的gzip格式数据的header,自己立的falg,自己也要含着泪完成.
这个Interceptor的主要作用是
CacheInterceptor
-
proceed()前置逻辑
前置逻辑主要的事情就是获取之前的Cache,然后通过内容,最后修改时间或者eTag来判断,该Cache是否过期.
如果没有过期,那么就直接对这个Cache进行重新包装,生成一个Response,然后就直接返回了.后续的proceed(),后续的interceptor全部都不会执行,直接返回了. -
proceed()
跳转到RealInterceptorChain.proceed()创建指向CallServerInterceptor的Chain和从interceptors获取ConnectInterceptor. -
proceed()后置逻辑
后置的逻辑主要就是将获取到的Response通过put()进行保存,等待下一次请求.
这个Interceptor的主要作用还是在请求时直接查看是否存在缓存,存在就直接返回,不存在就继续调用.以及响应时,对Response进行缓存的作用.
ConnectInterceptor
-
proceed()前置逻辑
整个interceptor核心就这2行代码.
之前对于Stream、Connection的含义进行解释过了.
通过这个Stream来获取一个HttpCodec,
HttpCodec就是一个编码解码器.
点进去发现它是一个接口,实现类是Http1Codec和Http2Codec.
因为HTTP_0.9/1.0/1.1和HTTP_2.0的格式完全不一样,一个是文本一个是二进制.
所以会实现2个的Codec.
最后传递给CallServerInterceptor去调用.
注意看看newStream()方法,因个人水平有限,只能关注最核心的方法,也就是去追踪它的TCP连接建立的过程.
//1.建立一个Healthy的连接.
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
//2.追踪这个findHealthyConnection() -> findConnection()
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
pingIntervalMillis, connectionRetryEnabled);
//3.findConnection() -> connect()
// Do TCP + TLS handshakes. This is a blocking operation.
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
//4.connect() -> connectSocket()/establishProtocol()
//tcp连接
connectSocket(connectTimeout, readTimeout, call, eventListener);
//tls安全层连接
establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener);
//5.1 connectSocket() -> connectSocket()
Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
//5.2 establishProtocol() -> connectTls()
connectTls(connectionSpecSelector);
//6.1 connectSocket() -> connect()
socket.connect(address, connectTimeout);
//6.2 connectTls()
// Create the wrapper over the connected socket.
sslSocket = (SSLSocket) sslSocketFactory.createSocket(
rawSocket, address.url().host(), address.url().port(), true /* autoClose */);
-
proceed()
跳转到RealInterceptorChain.proceed()创建指向" "的Chain和从interceptors获取CallServerInterceptor. -
proceed()后置逻辑
它木有后置逻辑啊,直接将proceed()的结果返回出去了.
这个Interceptor的主要作用还是建立一个TCP连接或者在TCP连接上面再建立一个TLS连接.
CallServerInterceptor
这是最后一个interceptor,他没有proceed().
这个Interceptor得到主要作用就是通过Codec编码解码器去沟通Socket,将Request写入进去,将Response读取回来.
比如:
httpCodec.writeRequestHeaders(request);
responseBuilder = httpCodec.readResponseHeaders(true);
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
具体太细节的我也不太懂,只是了解大概干了什么.
这就是最后一个,也就是CallServerInterceptor做的事情.
对于整个流程最好还是结合一下我画的图,再看一遍.
自定义Interceptor
看到这里,对于OkHttp的5大Interceptor相信都有所了解了.
那么自定义的Interceptor有哪些场景呢?
我这边个人使用到的,主要有2个.
- Logger信息打印,将每次请求的请求体打印出来,最后再将对应的响应内容打印出来.
很直观.(google请搜索 Log Interceptor) - 由于公司POST请求数据传输都需要对body部分的内容进行安全校验,使用了MD5+盐的方式来防止数据未被篡改.自定义一个Interceptor,在chain内获取到request,进行处理,处理完成以后再放回到chain里面.省去了每次请求都需要进行单独MD5的工作.
最后总结.
整个OkHttp的源码解读就到这里结束了.
写起来发现难度很大,发现比Retrofit的难度更大,OkHttp的源码从结构到细节,都比Retrofit要复杂太多,毕竟是自己实现了TCP的连接.
最后给自己挖一个学习坑.
WebSocket学习预定 !!!