本篇基于 okhttp 4.9.3 进行分析学习。
前言
Android 项目开发中离不开网络请求,说到网络请求一定会想到 okhttp。
okhttp 是如何完成一次请求的呢,接下来我们一步步来分析。
首先看下完整的流程图,此处直接使用 Piasy 大佬的图
一、如何发起请求
1. Android 工程中使用配置
添加网络请求权限 <uses-permission android:name="android.permission.INTERNET"/>
添加依赖 implementation "com.squareup.okhttp3:okhttp:4.9.3"
2. 发起请求
以发送 GET
请求为例,其他类型请求也是通过在创建 requst
对象时进行设置。
// 创建 OkHttpClient 实例对象,设置了超时时间
val client = OkHttpClient.Builder()
.callTimeout(10, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build()
// 创建 requset 对象,设置 url、请求方式、header 等信息
val request = Request.Builder().url(url).build()
// 同步执行,需放到子线程中执行
GlobalScope.launch(Dispatchers.IO) {
val response = client.newCall(request).execute().body?.string()
}
// 异步执行
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.d(TAG, e.message ?: "have IOException")
}
override fun onResponse(call: Call, response: Response) {
val response = response.body?.string()
Log.d(TAG, "enqueue() response = $response")
}
})
二、发起一次请求都经历了什么
分析上面 GET
请求时用到的对象,源码只保留流程中重要的部分。
1. OkHttpClient
open class OkHttpClient internal constructor(
builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
...
// OkHttpClient 可以构建 Call 的原因,因为实现了 Call.Factory
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
...
// 默认构建参数
class Builder constructor() {
internal var dispatcher: Dispatcher = Dispatcher() // 调度器
internal var connectionPool: ConnectionPool = ConnectionPool() // 连接池
internal val interceptors: MutableList<Interceptor> = mutableListOf() // 拦截器
internal val networkInterceptors: MutableList<Interceptor> = mutableListOf() // 网络拦截器
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
internal var retryOnConnectionFailure = true // 连接失败时重试
internal var authenticator: Authenticator = Authenticator.NONE // 验证器
internal var followRedirects = true // 允许重定向
internal var followSslRedirects = true // 允许 https 同 http 之间的重定向
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES // cookie
internal var cache: Cache? = null // 缓存
internal var dns: Dns = Dns.SYSTEM
internal var proxy: Proxy? = null
internal var proxySelector: ProxySelector? = null
internal var proxyAuthenticator: Authenticator = Authenticator.NONE
internal var socketFactory: SocketFactory = SocketFactory.getDefault()
internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
internal var x509TrustManagerOrNull: X509TrustManager? = null
internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
internal var certificateChainCleaner: CertificateChainCleaner? = null
internal var callTimeout = 0
internal var connectTimeout = 10_000
internal var readTimeout = 10_000
internal var writeTimeout = 10_000
internal var pingInterval = 0
internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
internal var routeDatabase: RouteDatabase? = null
// 传入自己构建的参数
internal constructor(okHttpClient: OkHttpClient) : this() {
this.dispatcher = okHttpClient.dispatcher
this.connectionPool = okHttpClient.connectionPool
this.interceptors += okHttpClient.interceptors
this.networkInterceptors += okHttpClient.networkInterceptors
this.eventListenerFactory = okHttpClient.eventListenerFactory
this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure
this.authenticator = okHttpClient.authenticator
this.followRedirects = okHttpClient.followRedirects
this.followSslRedirects = okHttpClient.followSslRedirects
this.cookieJar = okHttpClient.cookieJar
this.cache = okHttpClient.cache
this.dns = okHttpClient.dns
this.proxy = okHttpClient.proxy
this.proxySelector = okHttpClient.proxySelector
this.proxyAuthenticator = okHttpClient.proxyAuthenticator
this.socketFactory = okHttpClient.socketFactory
this.sslSocketFactoryOrNull = okHttpClient.sslSocketFactoryOrNull
this.x509TrustManagerOrNull = okHttpClient.x509TrustManager
this.connectionSpecs = okHttpClient.connectionSpecs
this.protocols = okHttpClient.protocols
this.hostnameVerifier = okHttpClient.hostnameVerifier
this.certificatePinner = okHttpClient.certificatePinner
this.certificateChainCleaner = okHttpClient.certificateChainCleaner
this.callTimeout = okHttpClient.callTimeoutMillis
this.connectTimeout = okHttpClient.connectTimeoutMillis
this.readTimeout = okHttpClient.readTimeoutMillis
this.writeTimeout = okHttpClient.writeTimeoutMillis
this.pingInterval = okHttpClient.pingIntervalMillis
this.minWebSocketMessageToCompress = okHttpClient.minWebSocketMessageToCompress
this.routeDatabase = okHttpClient.routeDatabase
}
...
}
使用建造者模式,用来设置拦截器、超时时间、缓存、重定向等属性。
2. Request
class Request internal constructor(
@get:JvmName("url") val url: HttpUrl,
@get:JvmName("method") val method: String,
@get:JvmName("headers") val headers: Headers,
@get:JvmName("body") val body: RequestBody?,
internal val tags: Map<Class<*>, Any>
) {
...
open class Builder {
internal var url: HttpUrl? = null
internal var method: String
internal var headers: Headers.Builder
internal var body: RequestBody? = null
internal var tags: MutableMap<Class<*>, Any> = mutableMapOf()
constructor() {
this.method = "GET"
this.headers = Headers.Builder()
}
internal constructor(request: Request) {
this.url = request.url
this.method = request.method
this.body = request.body
this.tags = if (request.tags.isEmpty()) {
mutableMapOf()
} else {
request.tags.toMutableMap()
}
this.headers = request.headers.newBuilder()
}
open fun url(url: HttpUrl): Builder = apply {
this.url = url
}
...
}
也是使用建造者模式,来设置请求方法、url、请求体、header 信息。
3. Call
interface Call : Cloneable {
// 返回 call 的 request 对象
fun request(): Request
// 执行同步请求
@Throws(IOException::class)
fun execute(): Response
// 执行异步请求
fun enqueue(responseCallback: Callback)
// 取消
fun cancel()
// 是否已经执行请求
fun isExecuted(): Boolean
// 是否已经取消
fun isCanceled(): Boolean
// 超时信息
fun timeout(): Timeout
// 克隆当前 call,返回新的对象方便再次执行请求,同一个 call 只能执行一次
public override fun clone(): Call
fun interface Factory {
fun newCall(request: Request): Call
}
}
接口类,定义了在一次请求中可能用到的方法。
4. RealCall
实现 Call 接口,是最终的请求执行者,下面按同步请求和异步请求分成两部分来说。
a、同步请求部分
// RealCall.execute
override fun execute(): Response {
// 每个 call 只能请求一次
check(executed.compareAndSet(false, true)) { "Already Executed" }
timeout.enter()
callStart()
try {
// 将当前 call 添加到 Dispatcher 类的 runningSyncCalls 列表中
client.dispatcher.executed(this)
// 经过一系列拦截器拿到请求结果
return getResponseWithInterceptorChain()
} finally {
// 将当前 call 从 Dispatcher 类的 runningSyncCalls 列表中移除
client.dispatcher.finished(this)
}
}
// RealCall.getResponseWithInterceptorChain
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf<Interceptor>()
// 开始添加拦截器
// 在 OkHttpClient 中设置的 拦截器
interceptors += client.interceptors
// 处理重试和重定向的拦截器
interceptors += RetryAndFollowUpInterceptor(client)
// 将应用请求转换为网络请求,将请求结果转换为用户友好响应的拦截器
interceptors += BridgeInterceptor(client.cookieJar)
// 读取缓存、更新缓存的拦截器
interceptors += CacheInterceptor(client.cache)
// 和服务器连接的拦截器
interceptors += ConnectInterceptor
if (!forWebSocket) {
// 在 OkHttpClient 中设置的 networkInterceptors
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)
}
}
}
主要处理逻辑在 getResponseWithInterceptorChain()
该方法中,dispatcher
用来改变执行状态。
b、异步请求部分
// RealCall.enqueue
override fun enqueue(responseCallback: Callback) {
// 每个 call 只能请求一次
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()
// 将 AsyncCall 添加到 Dispatcher.readyAsyncCalls 中
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
接下来看 enqueue()
方法
// Dispatcher.enqueue
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
// 添加到 readyAsyncCalls 中
readyAsyncCalls.add(call)
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.call.forWebSocket) {
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
promoteAndExecute()
}
接下来看 promoteAndExecute()
方法
// Dispatcher.promoteAndExecute
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
// 遍历 readyAsyncCalls
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 中
executableCalls.add(asyncCall)
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
// 遍历 executableCalls 开始执行
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
return isRunning
}
执行的 run 方法
// RealCall#AsyncCall.run
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)
}
}
}
看到这里再去看开头的流程图就很容易了
分析了请求的大致流程,细节分析后续有待完善。
网友评论