目的:主要是分析使用execute方法獲取response
測試類,建議放到idea里面,對照查看分析。
/**
* implementation("com.squareup.okhttp3:okhttp:4.9.3")
* implementation("com.squareup.okhttp3:logging-interceptor:4.9.3")
* */
object MainApp {
private val TAG = javaClass.simpleName
private val okHttpClient = createClient()
@JvmStatic
fun test() {
val request = Request.Builder().get().url("http://www.baidu.com").build()
try {
/**1.開始執(zhí)行請求[RealCall.execute]==>
* 2.獲取一個請求攔截器鏈,執(zhí)行各個攔截器赏半,最后返回response[RealCall.getResponseWithInterceptorChain]。
* */
val call = okHttpClient.newCall(request)
//call.timeout().timeout(30,TimeUnit.MILLISECONDS)//設置單個請求的超時時間淆两。具體實現(xiàn)查看[AsyncTimeout]
val resp = call.execute()
Log.d(TAG, "resp==" + resp.body?.string())
} catch (e: Exception) {
e.printStackTrace()
}
}
@JvmStatic
private fun createClient(): OkHttpClient {
return OkHttpClient.Builder()
/**
* 整個調用過程的超時時間:解析DNS断箫、連接、寫入請求體琼腔、服務器處理和讀取響應體瑰枫。
* 如果調用需要重定向或重試,所有這些都必須在一個超時時間內完成丹莲。
* 整個請求開始到結束的時間光坝,如果超時,會調用cancel方法甥材,會拋出InterruptedIOException("timeout")異常盯另。
* 單個請求設置方法 call.timeout().timeout(30,TimeUnit.MILLISECONDS)
* 如果是異步請求,則是call的run執(zhí)行開始計時洲赵。
* */
.callTimeout(20, TimeUnit.SECONDS)
//連接超時鸳惯,socket的連接時間商蕴,攔截器里面可以設置
.connectTimeout(10, TimeUnit.SECONDS)
//讀取超時,socket讀取數(shù)據(jù)超時時間芝发,攔截器里面可以設置
.readTimeout(10, TimeUnit.SECONDS)
//寫入超時绪商,socket發(fā)送數(shù)據(jù)超時時間,攔截器里面可以設置
.writeTimeout(10, TimeUnit.SECONDS)
//攔截器辅鲸,在攔截器最開始就會被調用
.addInterceptor(Interceptor { chain ->
Log.d(TAG, "Interceptor AA1 ")
return@Interceptor chain.proceed(chain.request())
})
.addInterceptor(Interceptor { chain ->
Log.d(TAG, "Interceptor AA2 ")
return@Interceptor chain.proceed(chain.request())
})
//執(zhí)行請求的攔截器格郁,在請求的http,socket連接之后才會調用独悴。
.addNetworkInterceptor(Interceptor { chain ->
Log.d(TAG, "NET Interceptor BB1 ")
return@Interceptor chain.proceed(chain.request())
})
//打印log
.addInterceptor(HttpLoggingInterceptor {
Log.d("HTTPLOG", it)
}.setLevel(HttpLoggingInterceptor.Level.BODY))
//請求調度和執(zhí)行例书。異步調用的線程池管理,記錄所有的請求(同步異步的都記錄)刻炒。
// 調用cancelAll决采,可以取消當前所有請求。
.dispatcher(Dispatcher())
.build()
}
}
執(zhí)行Call的execute方法坟奥,最后是RealCall.getResponseWithInterceptorChain方法獲取response树瞭,主要看這個方法就好。
execute方法
override fun execute(): Response {
check(executed.compareAndSet(false, true)) { "Already Executed" }
//okhttp.builder.callTimeout筏勒,從這里開始計時移迫。
//如果超時時間內,還沒有返回response管行,就會返回timeout厨埋。
//如果一個請求,整個流程要在10s內結束荡陷,不管連接、讀寫時間唉地,
//反正10s內要結束朱盐,就可以設置這個參數(shù)骇径。
timeout.enter()
callStart()
try {
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
1.[RealCall.getResponseWithInterceptorChain]
/** 1.[RealCall.getResponseWithInterceptorChain] */
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors//OkHttp創(chuàng)建時添加的攔截器[OkHttpClient.Builder.addInterceptor]
interceptors += RetryAndFollowUpInterceptor(client)//重試钱烟,重定向等
interceptors += BridgeInterceptor(client.cookieJar)//添加部分請求頭數(shù)據(jù),必要的請求頭
interceptors += CacheInterceptor(client.cache)//緩存處理
interceptors += ConnectInterceptor//http連接迄沫,主要是socket連接,給出接收和發(fā)送數(shù)據(jù)的操作封裝Exchange,供后面的攔截器使用
if (!forWebSocket) {
interceptors += client.networkInterceptors//[OkHttpClient.Builder.addNetworkInterceptor]
}
interceptors += CallServerInterceptor(forWebSocket)//發(fā)送睬捶、接收和解析數(shù)據(jù),得到服務器Response。
//組裝執(zhí)行鏈,注意里面的參數(shù)和什么時候執(zhí)行翔烁,什么時候創(chuàng)建白华。
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,//攔截器
index = 0,//執(zhí)行攔截器的位置
exchange = null,//執(zhí)行到ConnectInterceptor時,才會創(chuàng)建贩耐。
request = originalRequest,//請求
connectTimeoutMillis = client.connectTimeoutMillis,//默認為[OkHttpClient.Builder.connectTimeout]
readTimeoutMillis = client.readTimeoutMillis,//默認為[OkHttpClient.Builder.readTimeout]
writeTimeoutMillis = client.writeTimeoutMillis//默認為[OkHttpClient.Builder.writeTimeout]
)
var calledNoMoreExchanges = false
try {
val response = chain.proceed(originalRequest)//開始執(zhí)行
if (isCanceled()) {
response.closeQuietly()
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
noMoreExchanges(null)
}
}
}
2.[RealInterceptorChain.proceed]
/**2.[RealInterceptorChain.proceed]*/
@Throws(IOException::class)
override fun proceed(request: Request): Response {
check(index < interceptors.size)
calls++
```
// Call the next interceptor in the chain.
val next = copy(index = index + 1, request = request)
val interceptor = interceptors[index]
/**
* 在執(zhí)行完一個interceptor之后弧腥,會使用chain.proceed(chain.request()),
* 這個chain是第一個RealInterceptorChain copy的(新的chain潮太,只是列表數(shù)據(jù)是初始的數(shù)據(jù))管搪,
* chain的參數(shù)每次改變都是新copy一個RealInterceptorChain。
*/
@Suppress("USELESS_ELVIS")
val response = interceptor.intercept(next) ?: throw NullPointerException(
"interceptor $interceptor returned null")
```
return response
}
后面只要弄清楚各個Interceptor的功能就行了铡买。
3.[RetryAndFollowUpInterceptor]
主要用于重定向或其他錯誤處理更鲁。
1.具體處理的錯誤碼看[RetryAndFollowUpInterceptor.followUpRequest]方法:
//找出響應接收[userResponse]的HTTP請求。
//這將添加身份驗證頭奇钞、遵循重定向或處理客戶端請求超時澡为。
//如果后續(xù)操作是不必要的或不適用的,則返回null景埃。
@Throws(IOException::class)
private fun followUpRequest(userResponse: Response, exchange: Exchange?): Request? {
val route = exchange?.connection?.route()
val responseCode = userResponse.code
val method = userResponse.request.method
when (responseCode) {
HTTP_PROXY_AUTH -> {
val selectedProxy = route!!.proxy
if (selectedProxy.type() != Proxy.Type.HTTP) {
throw ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy")
}
return client.proxyAuthenticator.authenticate(route, userResponse)
}
HTTP_UNAUTHORIZED -> return client.authenticator.authenticate(route, userResponse)
HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> {
return buildRedirectRequest(userResponse, method)
}
HTTP_CLIENT_TIMEOUT -> {
// 408's are rare in practice, but some servers like HAProxy use this response code. The
// spec says that we may repeat the request without modifications. Modern browsers also
// repeat the request (even non-idempotent ones.)
if (!client.retryOnConnectionFailure) {
// The application layer has directed us not to retry the request.
return null
}
val requestBody = userResponse.request.body
if (requestBody != null && requestBody.isOneShot()) {
return null
}
val priorResponse = userResponse.priorResponse
if (priorResponse != null && priorResponse.code == HTTP_CLIENT_TIMEOUT) {
// We attempted to retry and got another timeout. Give up.
return null
}
if (retryAfter(userResponse, 0) > 0) {
return null
}
return userResponse.request
}
HTTP_UNAVAILABLE -> {
...
return null
}
HTTP_MISDIRECTED_REQUEST -> {
...
return userResponse.request
}
else -> return null
}
}
2.重定向請求次數(shù)
/**
*Chrome遵循21個重定向;Firefox,curl和wget緊隨20;Safari是16;HTTP/1.0推薦5媒至。
*/
private const val MAX_FOLLOW_UPS = 20
4.[BridgeInterceptor]
這個里面主要是添加必要的請求頭信息,
比如:"Content-Type"谷徙,"Content-Length"拒啰,"Cookie","User-Agent"等完慧。
還有gzip相關處理谋旦。
5.[CacheInterceptor]
一句話,就是緩存處理骗随。
Serves requests from the cache and writes responses to the cache.
服務來自緩存的請求蛤织,并將響應寫入緩存。
6.[ConnectInterceptor]
會創(chuàng)建socket和加入連接池等鸿染,
okHttpClient配置[connectTimeout][readTimeout][writeTimeout]相關參數(shù)在這里起作用指蚜。
找到或創(chuàng)建一條數(shù)據(jù)交換通道(socket),返回設置Exchange用于操作request和Response,交給下一個攔截器處理涨椒。
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val realChain = chain as RealInterceptorChain
/**initExchange
==>[ExchangeFinder.find]
==>[ExchangeFinder.findHealthyConnection]
==>[ExchangeFinder.findConnection]
==>[RealConnection.connect(
connectTimeout,//超時相關參數(shù)
readTimeout,
writeTimeout,
pingIntervalMillis,
connectionRetryEnabled,
call,
eventListener
)]*/
val exchange = realChain.call.initExchange(chain)
//設置exchange,交給下一個攔截器處理
val connectedChain = realChain.copy(exchange = exchange)
return connectedChain.proceed(realChain.request)
}
7.client.networkInterceptors
socket連接之后摊鸡,就是OkHttpClient創(chuàng)建時addNetworkInterceptor里面的攔截器相關的處理了。
8.CallServerInterceptor
This is the last interceptor in the chain. It makes a network call to the server.
這就是最后一個執(zhí)行的攔截器蚕冬,注意是最后才開始執(zhí)行免猾,也是最先執(zhí)行完的一個攔截器。
使用exchange發(fā)送請求相關數(shù)據(jù)和接收解析返回的數(shù)據(jù)囤热。
可以理解為里面使用socket猎提,發(fā)送HTTP協(xié)議相關的數(shù)據(jù)和接收解析數(shù)據(jù)。
最后返回response旁蔼。
這里是得到了后臺數(shù)據(jù)給的response锨苏,并不代表最后execute就是返回這個response數(shù)據(jù)疙教。
比如RetryAndFollowUpInterceptor還要對response做解析處理,log攔截器會打印log等伞租,所有攔截器執(zhí)行完成贞谓,最后得到的response,才算整個請求完成葵诈。
總結
整個execute流程分析完成裸弦,至于里面的其他細節(jié),不做具體分析了作喘。
知道okhttp創(chuàng)建時理疙,各個參數(shù)的含義,攔截器執(zhí)行的順序和各自作用泞坦,
那么在使用時沪斟,就不會有太多迷茫的位置了。