目的:主要是分析使用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.开始执行请求[RealCall.execute]==>
* 2.获取一个请求拦截器链,执行各个拦截器,最后返回response[RealCall.getResponseWithInterceptorChain]。
* */
val call = okHttpClient.newCall(request)
//call.timeout().timeout(30,TimeUnit.MILLISECONDS)//设置单个请求的超时时间。具体实现查看[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执行开始计时。
* */
.callTimeout(20, TimeUnit.SECONDS)
//连接超时,socket的连接时间,拦截器里面可以设置
.connectTimeout(10, TimeUnit.SECONDS)
//读取超时,socket读取数据超时时间,拦截器里面可以设置
.readTimeout(10, TimeUnit.SECONDS)
//写入超时,socket发送数据超时时间,拦截器里面可以设置
.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())
})
//执行请求的拦截器,在请求的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))
//请求调度和执行。异步调用的线程池管理,记录所有的请求(同步异步的都记录)。
// 调用cancelAll,可以取消当前所有请求。
.dispatcher(Dispatcher())
.build()
}
}
执行Call的execute方法,最后是RealCall.getResponseWithInterceptorChain方法获取response,主要看这个方法就好。
execute方法
override fun execute(): Response {
check(executed.compareAndSet(false, true)) { "Already Executed" }
//okhttp.builder.callTimeout,从这里开始计时。
//如果超时时间内,还没有返回response,就会返回timeout。
//如果一个请求,整个流程要在10s内结束,不管连接、读写时间,
//反正10s内要结束,就可以设置这个参数。
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创建时添加的拦截器[OkHttpClient.Builder.addInterceptor]
interceptors += RetryAndFollowUpInterceptor(client)//重试,重定向等
interceptors += BridgeInterceptor(client.cookieJar)//添加部分请求头数据,必要的请求头
interceptors += CacheInterceptor(client.cache)//缓存处理
interceptors += ConnectInterceptor//http连接,主要是socket连接,给出接收和发送数据的操作封装Exchange,供后面的拦截器使用
if (!forWebSocket) {
interceptors += client.networkInterceptors//[OkHttpClient.Builder.addNetworkInterceptor]
}
interceptors += CallServerInterceptor(forWebSocket)//发送、接收和解析数据,得到服务器Response。
//组装执行链,注意里面的参数和什么时候执行,什么时候创建。
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,//拦截器
index = 0,//执行拦截器的位置
exchange = null,//执行到ConnectInterceptor时,才会创建。
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)//开始执行
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]
/**
* 在执行完一个interceptor之后,会使用chain.proceed(chain.request()),
* 这个chain是第一个RealInterceptorChain copy的(新的chain,只是列表数据是初始的数据),
* chain的参数每次改变都是新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请求。
//这将添加身份验证头、遵循重定向或处理客户端请求超时。
//如果后续操作是不必要的或不适用的,则返回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.重定向请求次数
/**
*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]
会创建socket和加入连接池等,
okHttpClient配置[connectTimeout][readTimeout][writeTimeout]相关参数在这里起作用。
找到或创建一条数据交换通道(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,//超时相关参数
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创建时addNetworkInterceptor里面的拦截器相关的处理了。
8.CallServerInterceptor
This is the last interceptor in the chain. It makes a network call to the server.
这就是最后一个执行的拦截器,注意是最后才开始执行,也是最先执行完的一个拦截器。
使用exchange发送请求相关数据和接收解析返回的数据。
可以理解为里面使用socket,发送HTTP协议相关的数据和接收解析数据。
最后返回response。
这里是得到了后台数据给的response,并不代表最后execute就是返回这个response数据。
比如RetryAndFollowUpInterceptor还要对response做解析处理,log拦截器会打印log等,所有拦截器执行完成,最后得到的response,才算整个请求完成。
总结
整个execute流程分析完成,至于里面的其他细节,不做具体分析了。
知道okhttp创建时,各个参数的含义,拦截器执行的顺序和各自作用,
那么在使用时,就不会有太多迷茫的位置了。
网友评论