源码查看
/**
* Opens a connection to the target server and proceeds to the next interceptor. The network might
* be used for the returned response, or to validate a cached response with a conditional GET.
*/
object ConnectInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
// 关键点获取exchange
val exchange = realChain.call.initExchange(chain)
// copy方法,构造传参创建RealInterceptorChain对象,前面有讲过,不再赘述
val connectedChain = realChain.copy(exchange = exchange)
// 通过proceed获取response
return connectedChain.proceed(realChain.request)
}
}
通过注释可知,该拦截器用于开启一个到指定server的连接,并处理下一个拦截器。该网络可能用于返回response或者通过发起get请求来刷新response。
1、RealCall中initExchange(chain)方法
查找一个新的或者缓存池中的连接,用于即将到来的request和response
/** Finds a new or pooled connection to carry a forthcoming request and response. */
internal fun initExchange(chain: RealInterceptorChain): Exchange {
// 同步代码块检查状态
synchronized(this) {
check(expectMoreExchanges) { "released" }
check(!responseBodyOpen)
check(!requestBodyOpen)
}
val exchangeFinder = this.exchangeFinder!!
// 1.1 查询codec
val codec = exchangeFinder.find(client, chain)
// 1.2 构建exchange,用于处理IO操作
val result = Exchange(this, eventListener, exchangeFinder, codec)
// 缓存interceptorScopedExchange
this.interceptorScopedExchange = result
// 对exchange进行赋值操作
this.exchange = result
// 修改requestBodyOpen、responseBodyOpen状态值
synchronized(this) {
this.requestBodyOpen = true
this.responseBodyOpen = true
}
// 如果处理过程中被取消,抛出io异常
if (canceled) throw IOException("Canceled")
return result
}
- 1.1 ExchangeFinder的exchangeFinder.find(client, chain)
fun find(
client: OkHttpClient,
chain: RealInterceptorChain
): ExchangeCodec {
try {
// 1.1.1 查询HealthyConnection
val resultConnection = findHealthyConnection(
connectTimeout = chain.connectTimeoutMillis,
readTimeout = chain.readTimeoutMillis,
writeTimeout = chain.writeTimeoutMillis,
pingIntervalMillis = client.pingIntervalMillis,
connectionRetryEnabled = client.retryOnConnectionFailure,
doExtensiveHealthChecks = chain.request.method != "GET"
)
// 1.1.2 通过resultConnection 获取ExchangeCodec实例
return resultConnection.newCodec(client, chain)
} catch (e: RouteException) {
// 跟踪异常处理
trackFailure(e.lastConnectException)
throw e
} catch (e: IOException) {
trackFailure(e)
throw RouteException(e)
}
}
- 1.1.1 ExchangeFinder的findHealthyConnection()
1、返回一个连接到主机的流,优先选择存的的连接,未找到的话会从连接池中进行查找,最后仍未发现的话会创建新的连接。
2、每次运行查询前检查该连接是否被取消
/**
* Returns a connection to host a new stream. This prefers the existing connection if it exists,
* then the pool, finally building a new connection.
*
* This checks for cancellation before each blocking operation.
*/
@Throws(IOException::class)
private fun findConnection(
connectTimeout: Int,
readTimeout: Int,
writeTimeout: Int,
pingIntervalMillis: Int,
connectionRetryEnabled: Boolean
): RealConnection {
if (call.isCanceled()) throw IOException("Canceled")
// 通过call尝试复用连接
// Attempt to reuse the connection from the call.
// This may be mutated by releaseConnectionNoEvents()!
val callConnection = call.connection
if (callConnection != null) {
var toClose: Socket? = null
synchronized(callConnection) {
// 没有新的exchange或者不是相同的host和port
if (callConnection.noNewExchanges || !sameHostAndPort(callConnection.route().address.url)) {
// 释放socket连接
toClose = call.releaseConnectionNoEvents()
}
}
// If the call's connection wasn't released, reuse it. We don't call connectionAcquired() here
// because we already acquired it.
// call的连接不为空,复用连接
if (call.connection != null) {
check(toClose == null)
return callConnection
}
// The call's connection was released.
// toClose不为空,关闭socket
toClose?.closeQuietly()
eventListener.connectionReleased(call, callConnection)
}
// We need a new connection. Give it fresh stats.
// 创建新连接,刷新状态值
refusedStreamCount = 0
connectionShutdownCount = 0
otherFailureCount = 0
// Attempt to get a connection from the pool.
// 尝试从连接池中获取连接
if (connectionPool.callAcquirePooledConnection(address, call, null, false)) {
val result = call.connection!!
eventListener.connectionAcquired(call, result)
return result
}
// Nothing in the pool. Figure out what route we'll try next.
// 未从连接池中查找到连接,尝试找出route(路由)
val routes: List<Route>?
val route: Route
if (nextRouteToTry != null) {
// 路由不为空,合并连接
// Use a route from a preceding coalesced connection.
routes = null
route = nextRouteToTry!!
// 将nextRouteToTry置空
nextRouteToTry = null
} else if (routeSelection != null && routeSelection!!.hasNext()) {
// 使用现有的routeSelection
// Use a route from an existing route selection.
routes = null
route = routeSelection!!.next()
} else {
// Compute a new route selection. This is a blocking operation!
// 计算一个新的routeSelection 阻塞操作
var localRouteSelector = routeSelector
if (localRouteSelector == null) {
// 创建RouteSelector
localRouteSelector = RouteSelector(address, call.client.routeDatabase, call, eventListener)
this.routeSelector = localRouteSelector
}
// 通过localRouteSelector获取localRouteSelection
val localRouteSelection = localRouteSelector.next()
routeSelection = localRouteSelection
// 获取路由
routes = localRouteSelection.routes
if (call.isCanceled()) throw IOException("Canceled")
// Now that we have a set of IP addresses, make another attempt at getting a connection from
// the pool. We have a better chance of matching thanks to connection coalescing.
// 从connectionPool中获取已被回收的call中获取连接
if (connectionPool.callAcquirePooledConnection(address, call, routes, false)) {
val result = call.connection!!
eventListener.connectionAcquired(call, result)
return result
}
// 从localRouteSelection获取路由
route = localRouteSelection.next()
}
// Connect. Tell the call about the connecting call so async cancels work.
// 创建新的连接
val newConnection = RealConnection(connectionPool, route)
call.connectionToCancel = newConnection
try {
newConnection.connect(
connectTimeout,
readTimeout,
writeTimeout,
pingIntervalMillis,
connectionRetryEnabled,
call,
eventListener
)
} finally {
call.connectionToCancel = null
}
// 进行连接
call.client.routeDatabase.connected(newConnection.route())
// If we raced another call connecting to this host, coalesce the connections. This makes for 3
// different lookups in the connection pool!
// 如果连接支持多路复用,在连接池中查看三个不同的连接,确保连接的多路复用
if (connectionPool.callAcquirePooledConnection(address, call, routes, true)) {
// 通过call获取连接
val result = call.connection!!
nextRouteToTry = route
// 关闭socket
newConnection.socket().closeQuietly()
eventListener.connectionAcquired(call, result)
return result
}
// 将连接放到连接池中
synchronized(newConnection) {
connectionPool.put(newConnection)
call.acquireConnectionNoEvents(newConnection)
}
eventListener.connectionAcquired(call, newConnection)
// 返回连接
return newConnection
}
-
流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RE2YQ6tp-1629800296660)(evernotecid://995B5497-6FAA-4C24-AE87-2F5BD5F2399B/appyinxiangcom/18006758/ENResource/p168)] -
1.1.2 resultConnection.newCodec方法
@Throws(SocketException::class)
internal fun newCodec(client: OkHttpClient, chain: RealInterceptorChain): ExchangeCodec {
val socket = this.socket!!
val source = this.source!!
val sink = this.sink!!
val http2Connection = this.http2Connection
return if (http2Connection != null) {
// http2类型ExchangeCodec
Http2ExchangeCodec(client, this, chain, http2Connection)
} else {
// http1类型ExchangeCodec
socket.soTimeout = chain.readTimeoutMillis()
source.timeout().timeout(chain.readTimeoutMillis.toLong(), MILLISECONDS)
sink.timeout().timeout(chain.writeTimeoutMillis.toLong(), MILLISECONDS)
Http1ExchangeCodec(client, this, source, sink)
}
}
根据http2Connection判断使用Http2ExchangeCodec还是Http1ExchangeCodec作为具体实现类
- 1.2 构建 Exchange(this, eventListener, exchangeFinder, codec)
用于传递一个独立的请求和响应对,连接在ExchangeCodec上的管理和事件,用于处理实际的IO操作,实际上就是一个RealCall、EventListener、ExchangeFinder、ExchangeCodec的一个包装类,将参数及回调进行处理并通过EventListener将事件状态进行回调
/**
* Transmits a single HTTP request and a response pair. This layers connection management and events
* on [ExchangeCodec], which handles the actual I/O.
*/
class Exchange(
internal val call: RealCall,
internal val eventListener: EventListener,
internal val finder: ExchangeFinder,
private val codec: ExchangeCodec
) {
/** Returns true if the request body need not complete before the response body starts. */
internal var isDuplex: Boolean = false
private set
internal val connection: RealConnection = codec.connection
internal val isCoalescedConnection: Boolean
get() = finder.address.url.host != connection.route().address.url.host
// 写请求头
@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
}
}
// 创建请求体
@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)
}
// 刷新请求
@Throws(IOException::class)
fun flushRequest() {
try {
codec.flushRequest()
} catch (e: IOException) {
eventListener.requestFailed(call, e)
trackFailure(e)
throw e
}
}
// 完成请求
@Throws(IOException::class)
fun finishRequest() {
try {
codec.finishRequest()
} catch (e: IOException) {
eventListener.requestFailed(call, e)
trackFailure(e)
throw e
}
}
fun responseHeadersStart() {
eventListener.responseHeadersStart(call)
}
// 读取响应头
@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
}
}
fun responseHeadersEnd(response: Response) {
eventListener.responseHeadersEnd(call, response)
}
// 通过response构建RealResponseBody
@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
}
}
@Throws(IOException::class)
fun trailers(): Headers = codec.trailers()
// 创建webSocketStream
@Throws(SocketException::class)
fun newWebSocketStreams(): RealWebSocket.Streams {
call.timeoutEarlyExit()
return codec.connection.newWebSocketStreams(this)
}
fun webSocketUpgradeFailed() {
bodyComplete(-1L, responseDone = true, requestDone = true, e = null)
}
fun noNewExchangesOnConnection() {
codec.connection.noNewExchanges()
}
fun cancel() {
codec.cancel()
}
/**
* Revoke this exchange's access to streams. This is necessary when a follow-up request is
* required but the preceding exchange hasn't completed yet.
*/
fun detachWithViolence() {
codec.cancel()
call.messageDone(this, requestDone = true, responseDone = true, e = null)
}
private fun trackFailure(e: IOException) {
finder.trackFailure(e)
codec.connection.trackFailure(call, e)
}
fun <E : IOException?> bodyComplete(
bytesRead: Long,
responseDone: Boolean,
requestDone: Boolean,
e: E
): E {
if (e != null) {
trackFailure(e)
}
if (requestDone) {
if (e != null) {
eventListener.requestFailed(call, e)
} else {
eventListener.requestBodyEnd(call, bytesRead)
}
}
if (responseDone) {
if (e != null) {
eventListener.responseFailed(call, e)
} else {
eventListener.responseBodyEnd(call, bytesRead)
}
}
return call.messageDone(this, requestDone, responseDone, e)
}
fun noRequestBody() {
call.messageDone(this, requestDone = true, responseDone = false, e = null)
}
// 请求体压缩,实际上就是一个IO操作,同时将状态通过eventListener进行通知
/** A request body that fires events when it completes. */
private inner class RequestBodySink(
delegate: Sink,
/** The exact number of bytes to be written, or -1L if that is unknown. */
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)
}
}
/** A response body that fires events when it completes. */
internal inner class ResponseBodySource(
delegate: Source,
private val contentLength: Long
) : ForwardingSource(delegate) {
private var bytesReceived = 0L
private var invokeStartEvent = true
private var completed = false
private var closed = false
init {
if (contentLength == 0L) {
complete(null)
}
}
@Throws(IOException::class)
override fun read(sink: Buffer, byteCount: Long): Long {
check(!closed) { "closed" }
try {
val read = delegate.read(sink, byteCount)
if (invokeStartEvent) {
invokeStartEvent = false
eventListener.responseBodyStart(call)
}
if (read == -1L) {
complete(null)
return -1L
}
val newBytesReceived = bytesReceived + read
if (contentLength != -1L && newBytesReceived > contentLength) {
throw ProtocolException("expected $contentLength bytes but received $newBytesReceived")
}
bytesReceived = newBytesReceived
if (newBytesReceived == contentLength) {
complete(null)
}
return read
} catch (e: IOException) {
throw complete(e)
}
}
@Throws(IOException::class)
override fun close() {
if (closed) return
closed = true
try {
super.close()
complete(null)
} catch (e: IOException) {
throw complete(e)
}
}
fun <E : IOException?> complete(e: E): E {
if (completed) return e
completed = true
// If the body is closed without reading any bytes send a responseBodyStart() now.
if (e == null && invokeStartEvent) {
invokeStartEvent = false
eventListener.responseBodyStart(call)
}
return bodyComplete(bytesReceived, responseDone = true, requestDone = false, e = e)
}
}
}
- 参考: https://blog.csdn.net/heng615975867/article/details/105289872