一、网络执行
先贴代码:
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
val asyncCall = i.next()
if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
i.remove()
asyncCall.callsPerHost.incrementAndGet()
executableCalls.add(asyncCall)
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
return isRunning
}
可以看到这段代码的逻辑,先去判断最大请求数,然后判断单个域名最大请求数。然后再调用asyncCall.executeOn(executorService),从代码层面就能判断出这段是开启一个子线程去真正执行网络请求了。
fun executeOn(executorService: ExecutorService) {
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try {
executorService.execute(this)
success = true
} catch (e: RejectedExecutionException) {
val ioException = InterruptedIOException("executor rejected")
ioException.initCause(e)
noMoreExchanges(ioException)
responseCallback.onFailure(this@RealCall, ioException)
} finally {
if (!success) {
client.dispatcher.finished(this) // This call is no longer running!
}
}
}
果不其然用一个线程池去execute了,真正的执行开始了:
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
timeout.enter()
try {
val response = getResponseWithInterceptorChain()
signalledCallback = true
responseCallback.onResponse(this@RealCall, response)
} catch (e: IOException) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
} else {
responseCallback.onFailure(this@RealCall, e)
}
} catch (t: Throwable) {
cancel()
if (!signalledCallback) {
val canceledException = IOException("canceled due to $t")
canceledException.addSuppressed(t)
responseCallback.onFailure(this@RealCall, canceledException)
}
throw t
} finally {
client.dispatcher.finished(this)
}
}
}
}
这个方法里主要关注getResponseWithInterceptorChain方法的实现,是真实拿到网络结果,然后进行分发处理response。
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
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)
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
var calledNoMoreExchanges = false
try {
val response = chain.proceed(originalRequest)
if (isCanceled()) {
response.closeQuietly()
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
noMoreExchanges(null)
}
}
}
从这里可以看到一系列的拦截器,包括应用内自己加的,然后okhttp内置的一些。chain.proceed(originalRequest)就开始拦截器一个一个的执行了。
二、网络拦截器
- RetryAndFollowUpInterceptor :这个拦截器主要是进行请求重试、请求跟踪、异常处理相关的。
- BridgeInterceptor:主要作用是在应用程序的请求和网络请求之间架起一座"桥梁"
1.请求头的处理:添加基本的 HTTP 请求头(如果缺失),Content-Type、Content-Length/Transfer-Encoding、Host、Connection、Accept-Encoding (支持 gzip 压缩)、User-Agent,处理 Cookie(如果配置了 CookieJar),添加其他默认请求头
2.响应的处理:处理 gzip 压缩响应的解压,保存 Cookie(如果配置了 CookieJar),处理响应头 - CacheInterceptor:缓冲拦截器,主要来处理数据结果缓存逻辑,例如我们有需要的场景多长时间内不重复发起网络请求,取上次结果的,可以用到这个。
- ConnectInterceptor:负责建立网络连接的关键拦截器;
1.连接建立流程
2.连接池管理
3.超时控制
4.连接失败处理
5.连接复用
6.安全连接配置
7.连接监控
ConnectInterceptor 的主要优点:
连接复用、通过连接池管理复用连接、减少连接建立的开销、提高请求效率、自动重试、处理临时性网络问题、支持多域名切换、提高请求可靠性、性能优化、连接池大小根据CPU核心数优化、合理的超时设置、高效的连接管理、安全性、支持 HTTPS/TLS、证书验证、安全握手、可监控性、详细的连接生命周期事件、性能指标收集、异常信息记录
在实际应用中,ConnectInterceptor 通过这些机制确保了网络连接的:
高效性(连接复用)、可靠性(自动重试)、安全性(TLS支持)、可监控性(事件监听)
这使得 OkHttp 能够提供稳定高效的网络请求服务。 - CallServerInterceptor:拦截器链中的最后一个拦截器,负责执行实际的网络请求。