前言
终于!我们来到了ok内置五大拦截器最后一个拦截器的探究。关于这个拦截器我们直接来看一下源码的注释:
| This is the last interceptor in the chain. It makes a network call to the server. |
看到这里是不是有种拨开云雾见明月的感觉。话不多说我们继续先看下源码:
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
val exchange = realChain.exchange()
val request = realChain.request()
val requestBody = request.body
val sentRequestMillis = System.currentTimeMillis()
exchange.writeRequestHeaders(request)
var responseHeadersStarted = false
var responseBuilder: Response.Builder? = null
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
// If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
// Continue" response before transmitting the request body. If we don't get that, return
// what we did get (such as a 4xx response) without ever transmitting the request body.
if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
exchange.flushRequest()
responseHeadersStarted = true
exchange.responseHeadersStart()
responseBuilder = exchange.readResponseHeaders(true)
}
if (responseBuilder == null) {
if (requestBody.isDuplex()) {
// Prepare a duplex body so that the application can send a request body later.
exchange.flushRequest()
val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
requestBody.writeTo(bufferedRequestBody)
} else {
// Write the request body if the "Expect: 100-continue" expectation was met.
val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
requestBody.writeTo(bufferedRequestBody)
bufferedRequestBody.close()
}
} else {
exchange.noRequestBody()
if (!exchange.connection()!!.isMultiplexed) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
// from being reused. Otherwise we're still obligated to transmit the request body to
// leave the connection in a consistent state.
exchange.noNewExchangesOnConnection()
}
}
} else {
exchange.noRequestBody()
}
if (requestBody == null || !requestBody.isDuplex()) {
exchange.finishRequest()
}
if (!responseHeadersStarted) {
exchange.responseHeadersStart()
}
if (responseBuilder == null) {
responseBuilder = exchange.readResponseHeaders(false)!!
}
var response = responseBuilder
.request(request)
.handshake(exchange.connection()!!.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
var code = response.code
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
response = exchange.readResponseHeaders(false)!!
.request(request)
.handshake(exchange.connection()!!.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
code = response.code
}
exchange.responseHeadersEnd(response)
response = if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response.newBuilder()
.body(EMPTY_RESPONSE)
.build()
} else {
response.newBuilder()
.body(exchange.openResponseBody(response))
.build()
}
if ("close".equals(response.request.header("Connection"), ignoreCase = true) ||
"close".equals(response.header("Connection"), ignoreCase = true)) {
exchange.noNewExchangesOnConnection()
}
if ((code == 204 || code == 205) && response.body?.contentLength() ?: -1L > 0L) {
throw ProtocolException(
"HTTP $code had non-zero Content-Length: ${response.body?.contentLength()}")
}
return response
}
流程分析
是不是感觉臭长臭长的,但是莫慌!我们来一点一点攻克它。 我们先来看下面几行代码
val realChain = chain as RealInterceptorChain
val exchange = realChain.exchange()
val request = realChain.request()
val requestBody = request.body
val sentRequestMillis = System.currentTimeMillis()
这里几行基本上取出对应的参数,并且设置当前时间为请求发出时间。关键的是从realChain中取出Exchange对象,这个对象是后续操作的比较关键的,之前在connectInterceptor中构建出来并且传递到当前的。
接着网下看:通过 exchange.writeRequestHeaders(request)方法来开始写入请求头,接着根据请求方式和请求体是否为空来进入分支逻辑:
请求体不为空(主要针对POST请求)
100-continue
刚开始看到这里笔者也是有点懵逼的,这是什么鬼header。于是开始Google大法:
|
http 100-continue用于客户端在发送POST数据给服务器前,征询服务器情况,看服务器是否处理POST的数据,如果不处理,客户端则不上传POST数据,如果处理,则POST上传数据。在现实应用中,通常在POST大数据时,才会使用100-continue协议。 来源:https://zhuanlan.zhihu.com/p/30830041 |
接着就是读取响应头,同时通知eventListener响应头开始读取。我们看源码的调用链是调用ExchangeCodec的readResponseHeaders()方法来读取响应头,具体类似于BridgeInterceptor中的intercept方法。
紧接着根据responseBuilder是否为null来进入分支逻辑,这个responseBuilder是根据又是根据header中的Expect是否为100-continue来判断的。接下来就是比较简单了,根据request构建出来一个requesBody,并且把其写入到请求的body中。
请求体为空
请求体为null的情况下就比较简单了直接调用noRequestBody()方法。表示当前request阶段已经完成.
Response阶段
我们知道请求响应的开始也是从读取header。在上面经过发起Request结束之后,ok就已经做好准备进行response的接收。同样事件的发生也是会回调eventListener对应的监听。
var response = responseBuilder
.request(request)
.handshake(exchange.connection()!!.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
可以看到经过一系列操作,我们已经拿到了服务器的返回。最终就是通过:
response.newBuilder()
.body(exchange.openResponseBody(response))
.build()
这个方法来将服务端解析为客户端真正可用的resonse。
总结
CallServerInterceptor的流程解析基本上到这里就结束了。纵观ok内置几个拦截器的源码,其实都不是很复杂,内部是采用了优秀的设计模式将以此请求中的每个阶段都做了分层,然后采用递归调用的思想通过几个拦截器将一个请求由上而下、再由下而上的完成。其中的设计模式以及代码的分离都是非常值得我们来学习的。
基本上关于拦截器的分析到这里就告一段了。整个流程下来笔者对于ok内部的很多东西也是一笔带过,后续将会好机会再详细分析。通过对ok一次请求的整体流程的探究,深知纸上得来终觉浅,绝知此事要躬行,这句话也跟大家一起共勉。