簡(jiǎn)介
okhttp是Android中應(yīng)用最廣的http網(wǎng)絡(luò)請(qǐng)求框架。結(jié)構(gòu)優(yōu)雅煞茫,性能強(qiáng)大膜眠。我們通過(guò)閱讀它,對(duì)網(wǎng)絡(luò)庫(kù)的架構(gòu)進(jìn)行學(xué)習(xí)溜嗜。本篇主要閱讀okhttp的網(wǎng)絡(luò)請(qǐng)求攔截鏈模型。
基本結(jié)構(gòu)
okhttp采用拉截鏈的模型架谎,將網(wǎng)絡(luò)請(qǐng)求的各個(gè)部分炸宵,以一個(gè)個(gè)攔截器的方法,加入攔截鏈谷扣。
詳細(xì)代碼
我們知道土全,在okhttp的任務(wù)調(diào)度模型中捎琐,最終任務(wù),會(huì)調(diào)用execute
方法裹匙。我們先來(lái)看execute
方法瑞凑。
override fun execute() {
var signalledCallback = false
transmitter.timeoutEnter()
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(INFO, "Callback failure for ${toLoggableString()}", e)
} else {
responseCallback.onFailure(this@RealCall, e)
}
} finally {
client.dispatcher().finished(this)
}
}
這個(gè)方法中,實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的關(guān)鍵調(diào)用是:getResponseWithInterceptorChain
概页。其他主要還是調(diào)用回調(diào)或處理異常籽御。
拼裝攔截鏈
@Throws(IOException::class)
fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = ArrayList<Interceptor>()
interceptors.addAll(client.interceptors())
interceptors.add(RetryAndFollowUpInterceptor(client))
interceptors.add(BridgeInterceptor(client.cookieJar()))
interceptors.add(CacheInterceptor(client.internalCache()))
interceptors.add(ConnectInterceptor(client))
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors())
}
interceptors.add(CallServerInterceptor(forWebSocket))
val chain = RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis())
var calledNoMoreExchanges = false
try {
val response = chain.proceed(originalRequest)
if (transmitter.isCanceled) {
closeQuietly(response)
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw transmitter.noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null)
}
}
}
這塊兒代碼基本還是簡(jiǎn)單清晰的。先用ArrayList<Interceptor>
保存攔截器的隊(duì)列惰匙,然后生成RealInterceptorChain
技掏,最后調(diào)用proceed
方法,獲取response项鬼。
我們先來(lái)看攔截器的抽象實(shí)現(xiàn)哑梳。
/**
* Observes, modifies, and potentially short-circuits requests going out and the corresponding
* responses coming back in. Typically interceptors add, remove, or transform headers on the request
* or response.
*/
interface Interceptor {
@Throws(IOException::class)
fun intercept(chain: Chain): Response
companion object {
// This lambda conversion is for Kotlin callers expecting a Java SAM (single-abstract-method).
@JvmName("-deprecated_Interceptor")
inline operator fun invoke(
crossinline block: (chain: Chain) -> Response
): Interceptor = object : Interceptor {
override fun intercept(chain: Chain) = block(chain)
}
}
interface Chain {
fun request(): Request
@Throws(IOException::class)
fun proceed(request: Request): Response
/**
* Returns the connection the request will be executed on. This is only available in the chains
* of network interceptors; for application interceptors this is always null.
*/
fun connection(): Connection?
fun call(): Call
fun connectTimeoutMillis(): Int
fun withConnectTimeout(timeout: Int, unit: TimeUnit): Chain
fun readTimeoutMillis(): Int
fun withReadTimeout(timeout: Int, unit: TimeUnit): Chain
fun writeTimeoutMillis(): Int
fun withWriteTimeout(timeout: Int, unit: TimeUnit): Chain
}
}
intercept
方法,就是攔截器的核心绘盟,輸入Chain鸠真,返回Response。
我們隨意找一個(gè)Interceptor來(lái)進(jìn)行閱讀
RetryAndFollowUpInterceptor
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Transmitter transmitter = realChain.transmitter();
int followUpCount = 0;
Response priorResponse = null;
while (true) {
transmitter.prepareToConnect(request);
if (transmitter.isCanceled()) {
throw new IOException("Canceled");
}
Response response;
boolean success = false;
try {
response = realChain.proceed(request, transmitter, null);
success = true;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), transmitter, false, request)) {
throw e.getFirstConnectException();
}
continue;
}
...
}
這一段邏輯中龄毡,我們傳入的是chain吠卷,即整個(gè)攔截鏈,會(huì)在中間調(diào)用realChain.proceed()稚虎。表示撤嫩,在當(dāng)前攔截器中,我們只做我們職責(zé)之類的邏輯蠢终,其余的邏輯序攘,交給傳入Chain的下一環(huán)。
由此我們得知寻拂,RealInterceptorChain其實(shí)是一次請(qǐng)求所要做的所有工作程奠。每一個(gè)Interceptor只負(fù)責(zé)一部分工作。它們的順序是從外到內(nèi)祭钉,當(dāng)完成自己部分的外層功能后瞄沙,就會(huì)將接下來(lái)的工作,交給下一層去完成慌核。RetryAndFollowUpInterceptor只負(fù)責(zé)重試和重定向這些外層工作距境,其實(shí)邏輯會(huì)交由攔截器鏈的下一環(huán)節(jié)實(shí)現(xiàn)。Interceptor本身不用關(guān)心下一級(jí)的Interceptor是誰(shuí)垮卓。
接下來(lái)垫桂,我們?cè)倏匆幌拢琑ealInterceptorChain的邏輯粟按。
RealInterceptorChain
RealInterceptorChain中有一個(gè)index的索引霹粥。它標(biāo)識(shí)了當(dāng)前攔截器鏈路進(jìn)行到了哪一環(huán)。
我們著重看RealInterceptorChain的proceed
方法疼鸟,看一下Interceptor是如何前進(jìn)到下一環(huán)的后控。
class RealInterceptorChain(
private val interceptors: List<Interceptor>,
private val transmitter: Transmitter,
private val exchange: Exchange?,
private val index: Int,
private val request: Request,
private val call: Call,
private val connectTimeout: Int,
private val readTimeout: Int,
private val writeTimeout: Int
) : Interceptor.Chain {
private var calls: Int = 0
......
override fun proceed(request: Request): Response {
return proceed(request, transmitter, exchange)
}
@Throws(IOException::class)
fun proceed(request: Request, transmitter: Transmitter, exchange: Exchange?): Response {
if (index >= interceptors.size) throw AssertionError()
calls++
// If we already have a stream, confirm that the incoming request will use it.
if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
throw IllegalStateException("network interceptor " + interceptors[index - 1] +
" must retain the same host and port")
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.exchange != null && calls > 1) {
throw IllegalStateException("network interceptor " + interceptors[index - 1] +
" must call proceed() exactly once")
}
// Call the next interceptor in the chain.
val next = RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
val interceptor = interceptors[index]
@Suppress("USELESS_ELVIS")
val response = interceptor.intercept(next) ?: throw NullPointerException(
"interceptor $interceptor returned null")
// Confirm that the next interceptor made its required call to chain.proceed().
if (exchange != null && index + 1 < interceptors.size && next.calls != 1) {
throw IllegalStateException("network interceptor " + interceptor +
" must call proceed() exactly once")
}
if (response.body() == null) {
throw IllegalStateException(
"interceptor $interceptor returned a response with no body")
}
return response
}
}
這一段代碼首先對(duì)index進(jìn)行了檢查,然后對(duì)call,exchange中的種種參數(shù)進(jìn)行了檢查空镜。最后調(diào)用了
// Call the next interceptor in the chain.
val next = RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
val interceptor = interceptors[index]
@Suppress("USELESS_ELVIS")
val response = interceptor.intercept(next) ?: throw NullPointerException(
"interceptor $interceptor returned null")
調(diào)用當(dāng)前interceptor的intercept方法浩淘,并將下一個(gè)interceptor傳入。
小結(jié)
okhttp的網(wǎng)絡(luò)請(qǐng)求姑裂,采用了interceptor這樣的結(jié)構(gòu)馋袜,因?yàn)榫W(wǎng)絡(luò)請(qǐng)求是一個(gè)層級(jí)深,分支少的結(jié)構(gòu)舶斧。每一個(gè)層級(jí)并不關(guān)心下一個(gè)層級(jí)的實(shí)現(xiàn)欣鳖。因此,這樣的結(jié)構(gòu)很合適茴厉。
發(fā)散一下泽台,對(duì)于層級(jí)深,分支少矾缓,交付結(jié)果一致的業(yè)務(wù)模型怀酷,我們也可以采用這種interceptor的模型。方便層級(jí)之前解耦合嗜闻。
如有問(wèn)題蜕依,歡迎指正。