前言
OkHttp系列其他篇章
开篇
前面分别介绍了一些OkHttp的执行流程和OkHttp的前四个拦截器,还剩下最后一个拦截器,下面来看看CallServerInterceptor
连接拦截器都做了些什么
CallServerInterceptor
@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 invokeStartEvent = true
var responseBuilder: Response.Builder? = null
if (HttpMethod.permitsRequestBody(request.method) && requestBody != null) {
if ("100-continue".equals(request.header("Expect"), ignoreCase = true)) {
exchange.flushRequest()
responseBuilder = exchange.readResponseHeaders(expectContinue = true)
exchange.responseHeadersStart()
invokeStartEvent = false
}
if (responseBuilder == null) {
if (requestBody.isDuplex()) {
exchange.flushRequest()
val bufferedRequestBody = exchange.createRequestBody(request, true).buffer()
requestBody.writeTo(bufferedRequestBody)
} else {
val bufferedRequestBody = exchange.createRequestBody(request, false).buffer()
requestBody.writeTo(bufferedRequestBody)
bufferedRequestBody.close()
}
} else {
exchange.noRequestBody()
if (!exchange.connection.isMultiplexed) {
exchange.noNewExchangesOnConnection()
}
}
} else {
exchange.noRequestBody()
}
if (requestBody == null || !requestBody.isDuplex()) {
exchange.finishRequest()
}
if (responseBuilder == null) {
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
if (code == 100) {
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
if (invokeStartEvent) {
exchange.responseHeadersStart()
}
response = responseBuilder
.request(request)
.handshake(exchange.connection.handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build()
code = response.code
}
exchange.responseHeadersEnd(response)
response = if (forWebSocket && code == 101) {
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
}
exchange.writeRequestHeaders(request)
写入请求头信息- 判断请求方式是不是
GET
或HEAD
,如果不是则需要传入请求体,接着判断请求头中的Expect
值是否为100-continue
,如果是的话,则会读取响应体的头部信息,如果读出的Response.Builder
为空,接着判断requestBody.isDuplex()
,如果为true的话,则刷新缓冲区,通过exchange.createRequestBody(request, true).buffer()
创建bufferedRequestBody
,往请求的requestBody
写入数据,如果为false的话,,通过exchange.createRequestBody(request, true).buffer()
创建bufferedRequestBody
,写入输出流中发送数据。 - 如果请求方式是
GET
或HEAD
的话,则没有请求体。 - 如果
requestBody
为空,也就是没有请求体,或者requestBody.isDuplex()
为false的话,则结束请求。 - 如果responseBuilder为空的话,则调用
exchange.readResponseHeaders
方法 - 获取响应体
- 判断响应体的code是否为100,如果响应体为100 则是说后面还有数据需要传输,则会重新调用
exchange.readResponseHeaders
方法,再次生成响应体 - 判断code是否为101 并且 为websocekt请求,如果是的话,则生成一个空的response,否则就会通过
exchange.openResponseBody(response)
读取response中的数据生成一个响应体。 - 最后判断code是否为204、205并且响应体的body为空的话则抛出异常,否则正常返回。
总的来看其中有这几个重要的方法:
- 写入请求头
Exchange.writeRequestHeaders
- 创建请求体
Exchange.createRequestBody
- 写入请求体
requestBody.writeTo
- 读取响应头
Exchange.readResponseHeaders
- 读取响应体
Exchange.openResponseBody
可以看到ConnectInterceptor拦截器是通过Exchange类完成请求与响应的读写操作,而Exchange通过ExchangeCodec的实现类完成世纪的I/O操作,ExchangeCodec有两个主要的实现类(Http1ExchangeCodec
、Http2ExchangeCodec
),下面就从这两个不同的协议进行分析
下面分别来看看他们都干了些什么
Http1ExchangeCodec
Exchange.writeRequestHeaders
这个方法从名字就可以看出主要是写入请求头的作用,具体看看是如何写入的
@Throws(IOException::class)
fun writeRequestHeaders(request: Request) {
try {
eventListener.requestHeadersStart(call)
codec.writeRequestHeaders(request)
eventListener.requestHeadersEnd(call, request)
} catch (e: IOException) {
eventListener.requestFailed(call, e)
trackFailure(e)
throw e
}
}
override fun writeRequestHeaders(request: Request) {
val requestLine = RequestLine.get(request, connection.route().proxy.type())
writeRequest(request.headers, requestLine)
}
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
}
通过上面我们看一看出:
- 首先通过RequestLine.get方法构建一个http请求行,然后进行写入请求行,
- 循环遍历,取出请求头的key、value以utf-8的格式进行拼接写入
Exchange.createRequestBody
@Throws(IOException::class)
fun createRequestBody(request: Request, duplex: Boolean): Sink {
this.isDuplex = duplex
val contentLength = request.body!!.contentLength()
eventListener.requestBodyStart(call)
val rawRequestBody = codec.createRequestBody(request, contentLength)
return RequestBodySink(rawRequestBody, contentLength)
}
- 首先获取request.body的长度,然后再调用Http1ExchangeCodec.createRequestBody方法,将createRequestBody返回的sink对象用RequestBodySink对象包裹。
override fun createRequestBody(request: Request, contentLength: Long): Sink {
return when {
request.body != null && request.body.isDuplex() -> throw ProtocolException(
"Duplex connections are not supported for HTTP/1")
request.isChunked -> newChunkedSink()
contentLength != -1L -> newKnownLengthSink()
else ->
throw IllegalStateException(
"Cannot stream a request body without chunked encoding or a known content length!")
}
}
- 这里的过程就返回了一个
ChunkedSink
对象,下面看一个分析一下这个对象
private inner class ChunkedSink : Sink {
private val timeout = ForwardingTimeout(sink.timeout())
private var closed: Boolean = false
override fun timeout(): Timeout = timeout
override fun write(source: Buffer, byteCount: Long) {
check(!closed) { "closed" }
if (byteCount == 0L) return
sink.writeHexadecimalUnsignedLong(byteCount)
sink.writeUtf8("\r\n")
sink.write(source, byteCount)
sink.writeUtf8("\r\n")
}
@Synchronized
override fun flush() {
if (closed) return
sink.flush()
}
@Synchronized
override fun close() {
if (closed) return
closed = true
sink.writeUtf8("0\r\n\r\n")
detachTimeout(timeout)
state = STATE_READ_RESPONSE_HEADERS
}
}
这个类的功能 主要是处理I/O流,之后的i/o操作都会走这个类,可以看到写入的格式为\r\n+内容+\r\n。
在执行完createRequestBody
之后返回一个Sink对象,通过该Sink对象生成RequestBodySink对象进行返回。下面就来看看RequestBodySink这个类做了些什么
private inner class RequestBodySink(
delegate: Sink,
private val contentLength: Long
) : ForwardingSink(delegate) {
private var completed = false
private var bytesReceived = 0L
private var closed = false
@Throws(IOException::class)
override fun write(source: Buffer, byteCount: Long) {
check(!closed) { "closed" }
if (contentLength != -1L && bytesReceived + byteCount > contentLength) {
throw ProtocolException(
"expected $contentLength bytes but received ${bytesReceived + byteCount}")
}
try {
super.write(source, byteCount)
this.bytesReceived += byteCount
} catch (e: IOException) {
throw complete(e)
}
}
@Throws(IOException::class)
override fun flush() {
try {
super.flush()
} catch (e: IOException) {
throw complete(e)
}
}
@Throws(IOException::class)
override fun close() {
if (closed) return
closed = true
if (contentLength != -1L && bytesReceived != contentLength) {
throw ProtocolException("unexpected end of stream")
}
try {
super.close()
complete(null)
} catch (e: IOException) {
throw complete(e)
}
}
private fun <E : IOException?> complete(e: E): E {
if (completed) return e
completed = true
return bodyComplete(bytesReceived, responseDone = false, requestDone = true, e = e)
}
}
在这个类中可以看到,传入的sink对象,又通过构造方法传给了该类的父类,这个类所有I/O操作也全部是调用父类处方法,而父类又是交由传入的sink对象处理的,这里该类只是记录了一些关键信息。
requestBody.writeTo
这里的requestBody是一个抽象类,具体的实现都在他的实现类(FormBody
、MultipartBody
)中。下面先来看看requestBody的主要方法,以及主要功能
abstract class RequestBody {
abstract fun contentType(): MediaType?
open fun contentLength(): Long = -1L
@Throws(IOException::class)
abstract fun writeTo(sink: BufferedSink)
open fun isDuplex(): Boolean = false
open fun isOneShot(): Boolean = false
}
- contentType 代表当前请求体的格式 如text/html
- contentLength代表请求体的长度
- writeTo 往请求体写入操作
- isDuplex 代表当前的请求体中的写入读取全双工流是否可以常驻
- isOneShot 代表当前请求体是否只能使用一次,如果是遇到408,401,407等情况可以重复请求。此时需要这个标志位判断 其中主要的方法还是writeTo
FormBody
@Throws(IOException::class)
override fun writeTo(sink: BufferedSink) {
writeOrCountBytes(sink, false)
}
private fun writeOrCountBytes(sink: BufferedSink?, countBytes: Boolean): Long {
var byteCount = 0L
val buffer: Buffer = if (countBytes) Buffer() else sink!!.buffer
for (i in 0 until encodedNames.size) {
if (i > 0) buffer.writeByte('&'.toInt())
buffer.writeUtf8(encodedNames[i])
buffer.writeByte('='.toInt())
buffer.writeUtf8(encodedValues[i])
}
if (countBytes) {
byteCount = buffer.size
buffer.clear()
}
return byteCount
}
这里可以看到提交表单的格式为${encodedNames[i]}=${encodedValues[i]}
键值对的方式,注意FormBody只能传递键值对,不可以传递文件
MultipartBody
@Throws(IOException::class)
override fun writeTo(sink: BufferedSink) {
writeOrCountBytes(sink, false)
}
private fun writeOrCountBytes(
sink: BufferedSink?,
countBytes: Boolean
): Long {
var sink = sink
var byteCount = 0L
var byteCountBuffer: Buffer? = null
if (countBytes) {
byteCountBuffer = Buffer()
sink = byteCountBuffer
}
for (p in 0 until parts.size) {
val part = parts[p]
val headers = part.headers
val body = part.body
sink!!.write(DASHDASH)
sink.write(boundaryByteString)
sink.write(CRLF)
if (headers != null) {
for (h in 0 until headers.size) {
sink.writeUtf8(headers.name(h))
.write(COLONSPACE)
.writeUtf8(headers.value(h))
.write(CRLF)
}
}
val contentType = body.contentType()
if (contentType != null) {
sink.writeUtf8("Content-Type: ")
.writeUtf8(contentType.toString())
.write(CRLF)
}
val contentLength = body.contentLength()
if (contentLength != -1L) {
sink.writeUtf8("Content-Length: ")
.writeDecimalLong(contentLength)
.write(CRLF)
} else if (countBytes) {
byteCountBuffer!!.clear()
return -1L
}
sink.write(CRLF)
if (countBytes) {
byteCount += contentLength
} else {
body.writeTo(sink)
}
sink.write(CRLF)
}
sink!!.write(DASHDASH)
sink.write(boundaryByteString)
sink.write(DASHDASH)
sink.write(CRLF)
if (countBytes) {
byteCount += byteCountBuffer!!.size
byteCountBuffer.clear()
}
return byteCount
}
可以看出MultipartBody
提交表单的格式是下面这样的
-- ${UUID.randomUUID()} \r\n
${headers.name(h)} : ${headers.value(h)} \r\n
Content-Type: ${contentType.toString()} \r\n
Content-Length: ${contentLength}\r\n
-- ${UUID.randomUUID()} -- \r\n
MultipartBody
不仅可以提交键值对,还可以提交文件
Exchange.readResponseHeaders
@Throws(IOException::class)
fun readResponseHeaders(expectContinue: Boolean): Response.Builder? {
try {
val result = codec.readResponseHeaders(expectContinue)
result?.initExchange(this)
return result
} catch (e: IOException) {
eventListener.responseFailed(call, e)
trackFailure(e)
throw e
}
}
- 这里直接调用
Http1ExchangeCodec.readResponseHeaders
,所拥有的操作都在Http1ExchangeCodec中。
override fun readResponseHeaders(expectContinue: Boolean): Response.Builder? {
check(state == STATE_OPEN_REQUEST_BODY || state == STATE_READ_RESPONSE_HEADERS) {
"state: $state"
}
try {
val statusLine = StatusLine.parse(headersReader.readLine())
val responseBuilder = Response.Builder()
.protocol(statusLine.protocol)
.code(statusLine.code)
.message(statusLine.message)
.headers(headersReader.readHeaders())
return when {
expectContinue && statusLine.code == HTTP_CONTINUE -> {
null
}
statusLine.code == HTTP_CONTINUE -> {
state = STATE_READ_RESPONSE_HEADERS
responseBuilder
}
else -> {
state = STATE_OPEN_RESPONSE_BODY
responseBuilder
}
}
} catch (e: EOFException) {
val address = connection.route().address.url.redact()
throw IOException("unexpected end of stream on $address", e)
}
}
- headersReader包裹着在
RealConnection
中获取的socket输出流,通过headersReader.readLine()
读出状态行信息。 - 构建response对象,将statusLine.code、statusLine.message传入
- 通过headersReader.readHeaders()读出请求头信息 -如果code是101 则记录当前状态是STATE_READ_RESPONSE_HEADERS,否则就是STATE_OPEN_RESPONSE_BODY。并返回Response.Builder。
Exchange.openResponseBody
@Throws(IOException::class)
fun openResponseBody(response: Response): ResponseBody {
try {
val contentType = response.header("Content-Type")
val contentLength = codec.reportedContentLength(response)
val rawSource = codec.openResponseBodySource(response)
val source = ResponseBodySource(rawSource, contentLength)
return RealResponseBody(contentType, contentLength, source.buffer())
} catch (e: IOException) {
eventListener.responseFailed(call, e)
trackFailure(e)
throw e
}
}
- 从Response 中读取应答头部的Content-Type
- 从Response 中读取应答头部的Content-Length
- openResponseBodySource 生成一个ChunkedSource 对象,这个对象调用read方法读取时候,将会根据流读取socket输入流中的内容,知道长度为消费完毕。
- 生成一个ResponseBodySource 对象,持有ChunkedSource读取流以及contentLength。生成RealResponseBody 对象持有ResponseBodySource对象。返回RealResponseBody。
Http2ExchangeCodec
exchange.writeRequestHeaders(request)
@Throws(IOException::class)
fun writeRequestHeaders(request: Request) {
try {
eventListener.requestHeadersStart(call)
codec.writeRequestHeaders(request)
eventListener.requestHeadersEnd(call, request)
} catch (e: IOException) {
eventListener.requestFailed(call, e)
trackFailure(e)
throw e
}
}
override fun writeRequestHeaders(request: Request) {
if (stream != null) return
val hasRequestBody = request.body != null
val requestHeaders = http2HeadersList(request)
stream = http2Connection.newStream(requestHeaders, hasRequestBody)
if (canceled) {
stream!!.closeLater(ErrorCode.CANCEL)
throw IOException("Canceled")
}
stream!!.readTimeout().timeout(chain.readTimeoutMillis.toLong(), TimeUnit.MILLISECONDS)
stream!!.writeTimeout().timeout(chain.writeTimeoutMillis.toLong(), TimeUnit.MILLISECONDS)
}
在http2中的做法和http1有些不一样:
- 通过
http2HeadersList
方法从请求体中获取请求头信息,在这个方法中添加几个公共的请求头信息(TARGET_METHOD
、TARGET_PATH
、TARGET_AUTHORITY
、TARGET_SCHEME
).再将请求头重key全部转化为小写 - http2Connection.newStream 生成全新的Http2Stream,在该方法中进行对请求头的拼接写入。
@Throws(IOException::class)
private fun newStream(
associatedStreamId: Int,
requestHeaders: List<Header>,
out: Boolean
): Http2Stream {
val outFinished = !out
val inFinished = false
val flushHeaders: Boolean
val stream: Http2Stream
val streamId: Int
synchronized(writer) {
synchronized(this) {
if (nextStreamId > Int.MAX_VALUE / 2) {
shutdown(REFUSED_STREAM)
}
if (isShutdown) {
throw ConnectionShutdownException()
}
streamId = nextStreamId
nextStreamId += 2
stream = Http2Stream(streamId, this, outFinished, inFinished, null)
flushHeaders = !out ||
writeBytesTotal >= writeBytesMaximum ||
stream.writeBytesTotal >= stream.writeBytesMaximum
if (stream.isOpen) {
streams[streamId] = stream
}
}
if (associatedStreamId == 0) {
writer.headers(outFinished, streamId, requestHeaders)
} else {
require(!client) { "client streams shouldn't have associated stream IDs" }
writer.pushPromise(associatedStreamId, streamId, requestHeaders)
}
}
if (flushHeaders) {
writer.flush()
}
return stream
}
- 如果
nextStreamId > Int.MAX_VALUE / 2
,调用shutdown
关闭上一次读去过的头部信息流 nextStreamId
不断的加2成为新的streamId
,并创建Http2Stream
对象将streamid赋值给Http2Stream
,并将Http2Stream
保存在streams
集合中- 调用
Http2Writer
对象的headers
方法写入头部信息
@Synchronized @Throws(IOException::class)
fun headers(
outFinished: Boolean,
streamId: Int,
headerBlock: List<Header>
) {
if (closed) throw IOException("closed")
hpackWriter.writeHeaders(headerBlock)
val byteCount = hpackBuffer.size
val length = minOf(maxFrameSize.toLong(), byteCount)
var flags = if (byteCount == length) FLAG_END_HEADERS else 0
if (outFinished) flags = flags or FLAG_END_STREAM
frameHeader(
streamId = streamId,
length = length.toInt(),
type = TYPE_HEADERS,
flags = flags
)
sink.write(hpackBuffer, length)
if (byteCount > length) writeContinuationFrames(streamId, byteCount - length)
}
hpackWriter.writeHeaders(headerBlock)
把所有的请求头信息都会写入到一个hpackBuffer
的缓冲区,- 调用
frameHeader
方法构造头部信息进行写入 sink.write(hpackBuffer, length)
写入缓冲区的请求头
Exchange.createRequestBody
@Throws(IOException::class)
fun createRequestBody(request: Request, duplex: Boolean): Sink {
this.isDuplex = duplex
val contentLength = request.body!!.contentLength()
eventListener.requestBodyStart(call)
val rawRequestBody = codec.createRequestBody(request, contentLength)
return RequestBodySink(rawRequestBody, contentLength)
}
override fun createRequestBody(request: Request, contentLength: Long): Sink {
return stream!!.getSink()
}
这里就是获取到了Http2Stream
的sink对象,这个sink对象其实就是FramingSink
internal val sink = FramingSink(
finished = outFinished
)
那么这个sink对象就同上面Http1中的一样,由RequestBodySink包裹, 主要是处理I/O流,之后的i/o操作都会走这个类。
FramingSink write
override fun write(source: Buffer, byteCount: Long) {
this@Http2Stream.assertThreadDoesntHoldLock()
sendBuffer.write(source, byteCount)
while (sendBuffer.size >= EMIT_BUFFER_SIZE) {
emitFrame(false)
}
}
- 向sendBuffer缓冲区写入数据
- 如果数据量大小 大于 EMIT_BUFFER_SIZE调用emitFrame方法
@Throws(IOException::class)
private fun emitFrame(outFinishedOnLastFrame: Boolean) {
val toWrite: Long
val outFinished: Boolean
synchronized(this@Http2Stream) {
writeTimeout.enter()
try {
while (writeBytesTotal >= writeBytesMaximum &&
!finished &&
!closed &&
errorCode == null) {
waitForIo()
}
} finally {
writeTimeout.exitAndThrowIfTimedOut()
}
checkOutNotClosed()
toWrite = minOf(writeBytesMaximum - writeBytesTotal, sendBuffer.size)
writeBytesTotal += toWrite
outFinished = outFinishedOnLastFrame && toWrite == sendBuffer.size && errorCode == null
}
writeTimeout.enter()
try {
connection.writeData(id, outFinished, sendBuffer, toWrite)
} finally {
writeTimeout.exitAndThrowIfTimedOut()
}
}
- 如果在这个临时写入缓冲区中,已经大于
writeBytesMaximum
写入最大的数据荷载极限,那么就会阻塞该写入流程 - 调用 connection.writeData方法向socket中写入数据
@Throws(IOException::class)
fun writeData(
streamId: Int,
outFinished: Boolean,
buffer: Buffer?,
byteCount: Long
) {
if (byteCount == 0L) {
writer.data(outFinished, streamId, buffer, 0)
return
}
var byteCount = byteCount
while (byteCount > 0L) {
var toWrite: Int
synchronized(this@Http2Connection) {
try {
while (writeBytesTotal >= writeBytesMaximum) {
if (!streams.containsKey(streamId)) {
throw IOException("stream closed")
}
this@Http2Connection.wait()
}
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
throw InterruptedIOException()
}
toWrite = minOf(byteCount, writeBytesMaximum - writeBytesTotal).toInt()
toWrite = minOf(toWrite, writer.maxDataLength())
writeBytesTotal += toWrite.toLong()
}
byteCount -= toWrite.toLong()
writer.data(outFinished && byteCount == 0L, streamId, buffer, toWrite)
}
}
- 判断写入的数据是否大于最大数 writeBytesTotal >= writeBytesMaximum 如果大于则调用wait方法阻塞
- 调用writer.data 写入数据
@Synchronized @Throws(IOException::class)
fun data(outFinished: Boolean, streamId: Int, source: Buffer?, byteCount: Int) {
if (closed) throw IOException("closed")
var flags = FLAG_NONE
if (outFinished) flags = flags or FLAG_END_STREAM
dataFrame(streamId, flags, source, byteCount)
}
@Throws(IOException::class)
fun dataFrame(streamId: Int, flags: Int, buffer: Buffer?, byteCount: Int) {
frameHeader(
streamId = streamId,
length = byteCount,
type = TYPE_DATA,
flags = flags
)
if (byteCount > 0) {
sink.write(buffer!!, byteCount.toLong())
}
}
- 调用
frameHeader
方法构造头部信息进行写入 - 调用 sink.write 方法写入数据
Exchange.readResponseHeaders
override fun readResponseHeaders(expectContinue: Boolean): Response.Builder? {
val headers = stream!!.takeHeaders()
val responseBuilder = readHttp2HeadersList(headers, protocol)
return if (expectContinue && responseBuilder.code == HTTP_CONTINUE) {
null
} else {
responseBuilder
}
}
@Synchronized @Throws(IOException::class)
fun takeHeaders(): Headers {
readTimeout.enter()
try {
while (headersQueue.isEmpty() && errorCode == null) {
waitForIo()
}
} finally {
readTimeout.exitAndThrowIfTimedOut()
}
if (headersQueue.isNotEmpty()) {
return headersQueue.removeFirst()
}
throw errorException ?: StreamResetException(errorCode!!)
}
- 如果判断headersQueue.isEmpty()和errorCode == null是否为true,如果为true则阻塞当前线程,
- 如果headersQueue.isNotEmpty()则从headersQueue中获取到存入流的头部结果,进行返回
fun readHttp2HeadersList(headerBlock: Headers, protocol: Protocol): Response.Builder {
var statusLine: StatusLine? = null
val headersBuilder = Headers.Builder()
for (i in 0 until headerBlock.size) {
val name = headerBlock.name(i)
val value = headerBlock.value(i)
if (name == RESPONSE_STATUS_UTF8) {
statusLine = StatusLine.parse("HTTP/1.1 $value")
} else if (name !in HTTP_2_SKIPPED_RESPONSE_HEADERS) {
headersBuilder.addLenient(name, value)
}
}
if (statusLine == null) throw ProtocolException("Expected ':status' header not present")
return Response.Builder()
.protocol(protocol)
.code(statusLine.code)
.message(statusLine.message)
.headers(headersBuilder.build())
}
- 通过循环遍历获取到所有头部信息,创建状态行,将头部信息存入
namesAndValues
集合中 - 如果状态行对象为空,则抛出异常
- 通过headersBuilder.build构建
Headers
对象,将namesAndValues传入Headers对象当中 - 构建response对象,将statusLine.code、statusLine.message、Headers对象传入,进行返回
总结
CallServerIntercepter的拦截逻辑很简单,总的来说就是将请求头,请求体写入Socket,然后读取Socket的响应头和响应体。而具体的IO操作,OkHttp是采用的okio,这是个优秀的IO库,具体的逻辑这里就不深挖了。具体的流程如下:
- 写入请求头。
- 如果请求头里有"100-continue", 代表先将请求头发送给服务器,看服务器的响应决定是否进行下一步请求体的发送。
- 写入请求体,并发送请求。
- 读取响应体,并构建一个Resonse
- 如果响应码为100,需要再请求一次。
- 读取详细的响应体。
- 如果响应头有“close”,那么关闭这条连接。
- 返回响应。