文章目录
这个拦截器是干嘛的
前面我们已经通过ConnectInterceptor拦截器建立了连接(参见ConnectInterceptor拦截器), 那CallServerInterceptor就是发起真正的网络请求, 他是最后一个拦截器
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
//偶没有骗你, 他真的是最后一个拦截器
interceptors += CallServerInterceptor(forWebSocket)
主要流程
流程如下, 注意, 我们基于http1.1来进行讨论, 请求头里没有100-continue, 一切都以最简单的来
走读下代码
override fun intercept(chain: Interceptor.Chain): Response {
... 这里不用看了
try {
// 写入http header
exchange.writeRequestHeaders(request)
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
// 只有非GET和Head的请求, 才会写body
if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
... 这里流程忽略, 这里是给100-continue用的, 先不看吧
}
if (responseBuilder == null) {
if (requestBody.isDuplex()) {
... 这里也不看, 应该是给http2用的(存疑)
} else {
// 写request body
val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
requestBody.writeTo(bufferedRequestBody)
bufferedRequestBody.close()
}
} else {
// 对于GET请求, 根本就没有body好吧
exchange.noRequestBody()
...
}
} else {
exchange.noRequestBody()
}
...
//上面write 完毕, 开始read
try {
if (responseBuilder == null) {
// 先读取header
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
if (invokeStartEvent) {
exchange.responseHeadersStart()
invokeStartEvent = false
}
}
var response = responseBuilder
.request(request)
.handshake(exchange.connection.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
var code = response.code
... 这里忽略一些流程
// 对response source进行一些封装
response.newBuilder()
.body(exchange.openResponseBody(response))
.build()
return response
} catch (e: IOException) {
...
}
}
主流程就是上面那个, 还是有一些特别有意思的逻辑
request header是怎么写的?
看一下写header的代码
override fun writeRequestHeaders(request: Request) {
val requestLine = RequestLine.get(request, connection.route().proxy.type())
writeRequest(request.headers, requestLine)
}
将命令搞成一个字符串 requestLine
fun get(request: Request, proxyType: Proxy.Type) = buildString {
append(request.method)
append(' ')
if (includeAuthorityInRequestLine(request, proxyType)) {
append(request.url)
} else {
append(requestPath(request.url))
}
append(" HTTP/1.1")
}
开始正式写
fun writeRequest(headers: Headers, requestLine: String) {
check(state == STATE_IDLE) { "state: $state" }
sink.writeUtf8(requestLine).writeUtf8("\r\n")
for (i in 0 until headers.size) {
sink.writeUtf8(headers.name(i))
.writeUtf8(": ")
.writeUtf8(headers.value(i))
.writeUtf8("\r\n")
}
sink.writeUtf8("\r\n")
state = STATE_OPEN_REQUEST_BODY
}
这里的sink是哪里来的?
他其实就是来自我们ConnectInterceptor拦截器中的connectSocket
//来自connectSocket方法
try {
source = rawSocket.source().buffer()
sink = rawSocket.sink().buffer()
} catch (npe: NullPointerException) {
if (npe.message == NPE_THROW_WITH_NULL) {
throw IOException(npe)
}
}
为什么要封装response body, 不直接读出来
这里我们不应该忘记okhttp的基本用法
OkHttpClient client = new OkHttpClient();
//创建一个Request
Request request = new Request.Builder()
.get()
.url(url)
.build();
//通过client发起请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
// String str = response.body().string();
}
}
});
返回的结果还是要在response中读出来的
如果一个response还没有读取内容, 那怎么保证对应的connect不被复用, 不被分配给别人
我们在ConnectInterceptor中知道, 连接是复用的, 在发起Call的时候, 会优先从连接池中拿连接, 如果没有, 采取新建一个连接.
那怎么保证正在使用的连接,或者说已经有response返回了, 但是还没有被read的connect, 不被分配给别的call呢?
因为我们每次用完response中的outputStream之后, 都对其进行了close操作, close操作之后, 会释放掉RealCall中的RealConnection.
所以我们一定要进行close操作啊.
代码看下
在Exchange的openResponseBody中, 可以看到, 我们拿到的ResponseBody是RealResponseBody的实例, 其中, 关键的BufferedSource是ResponseBodySource的实例
@Throws(IOException::class)
fun openResponseBody(response: Response): ResponseBody {
try {
...
//注意这里, 是ResponseBodySource
val source = ResponseBodySource(rawSource, contentLength)
return RealResponseBody(contentType, contentLength, source.buffer())
} catch (e: IOException) {
eventListener.responseFailed(call, e)
trackFailure(e)
throw e
}
}
当我们调用了close方法之后, 实际上代码流程会这么走
最终会释放RealConnection中的calls.
而我们在ConnectInterceptor中看过下面的代码, 在申请连接的时候, 如果calls不为空, 那么就不选取这个连接
internal fun isEligible(address: Address, routes: List<Route>?): Boolean {
assertThreadHoldsLock()
// If this connection is not accepting new exchanges, we're done.
// 如果判断一个realConnection是否可以用,主要还是靠noNewExchange来的
if (calls.size >= allocationLimit || noNewExchanges) return false
...
}