通過(guò)前兩篇文章,大家對(duì)HTTP的許多概念及OkHttp的類結(jié)構(gòu)及使用已經(jīng)有了解,這篇主要講一下OKHttp的整個(gè)請(qǐng)求流程以及這中間涉及到的一些設(shè)計(jì)模式,過(guò)程中會(huì)忽略掉一些局部比較細(xì)節(jié)的問(wèn)題,這些忽略的部分會(huì)在后面的文章中繼續(xù)進(jìn)行深入講解。
發(fā)起請(qǐng)求
我們先看一下OKHttp最外層使用的形式:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
Call call = client.newCall(request);
//同步請(qǐng)求
Response response = call.execute();
//異步請(qǐng)求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//請(qǐng)求失敗
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//請(qǐng)求成功
}
});
如上代碼既是一般的使用流程,總結(jié)為4步:
1 創(chuàng)建OkHttpClient實(shí)例
2 創(chuàng)建Request實(shí)例
3 用client實(shí)例的newCall方法創(chuàng)建一個(gè)Call實(shí)例
4 調(diào)用Call的同步或異步請(qǐng)求方法,得到Response實(shí)例
對(duì)外部使用來(lái)說(shuō),這就完成了一次請(qǐng)求。
這4步涉及4個(gè)對(duì)象:OkHttpClient、Request、Call、Response。
Requst
首先看Requst對(duì)象,這個(gè)對(duì)象主要攜帶一些我們發(fā)出請(qǐng)求所需的數(shù)據(jù),比如請(qǐng)求地址、請(qǐng)求頭信息等,以下是它所有屬性:
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Object tag;
private volatile CacheControl cacheControl;
這幾個(gè)屬性都很簡(jiǎn)單:url即我們請(qǐng)求的地址;method即請(qǐng)求方法,默認(rèn)是GET,我們可以設(shè)置成POST等;headers是一些頭信息;body是RequestBody對(duì)象,這個(gè)對(duì)象可以幫我們向服務(wù)端傳送各種格式的數(shù)據(jù),后面會(huì)簡(jiǎn)單介紹一下;tag是這個(gè)Request對(duì)象的標(biāo)記,用來(lái)找到這個(gè)請(qǐng)求對(duì)象,以便在后續(xù)流程中進(jìn)行取消請(qǐng)求等操作;cacheControl用來(lái)控制緩存操作,設(shè)置此次請(qǐng)求是否需要緩存以及緩存時(shí)間等,這里不加詳述,后續(xù)文章中會(huì)有專門針對(duì)緩存的介紹。
再簡(jiǎn)單介紹一下RequestBody對(duì)象,這是一個(gè)抽象類,只有下面3個(gè)方法需要實(shí)現(xiàn):
public abstract @Nullable MediaType contentType();
public long contentLength() throws IOException {
return -1;
}
public abstract void writeTo(BufferedSink sink) throws IOException;
這個(gè)類還提供了5個(gè)快速創(chuàng)建實(shí)例的create方法,只需傳入MediaType和相應(yīng)的內(nèi)容數(shù)據(jù)即可創(chuàng)建實(shí)例,如下面代碼:
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
String json = "{name:abc,age:18}";
RequestBody body = RequestBody.create(JSON, json);
OkHttpClient
有了Request里的請(qǐng)求信息,就可以用OkHttpClient創(chuàng)建Call對(duì)象了,OkHttpClient
對(duì)象有很多屬性,這里不再一一列舉,可以理解它就是整個(gè)系統(tǒng)的上下文,收集了請(qǐng)求流程中會(huì)用到的各種數(shù)據(jù),這個(gè)對(duì)象本身也會(huì)在請(qǐng)求發(fā)起時(shí)向下傳遞。這里只關(guān)注一下例子中用到的newCall函數(shù),源碼如下:
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
可見(jiàn)這個(gè)函數(shù)實(shí)際返回了一共RealCall對(duì)象,一個(gè)Call的子類。RealCall構(gòu)造函數(shù)的第一個(gè)參數(shù)就是OkHttpClient的this,即把這個(gè)對(duì)象向下傳遞了,第二個(gè)參數(shù)是Request,就把請(qǐng)求信息傳遞了下去,第三個(gè)參數(shù)暫時(shí)不用關(guān)心,是關(guān)于web socket的。
Call & RealCall
Call是個(gè)接口,RealCall是它唯一的實(shí)現(xiàn)子類。通過(guò)其構(gòu)造函數(shù)我們知道RealCall里保存了OkHttpClient和Requst,對(duì)于外部調(diào)用來(lái)說(shuō)當(dāng)執(zhí)行execute或enqueue方法時(shí)才真正是網(wǎng)絡(luò)請(qǐng)求的開(kāi)始。
先看execute方法:
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
//將這個(gè)請(qǐng)求交給dispatcher管理
client.dispatcher().executed(this);
//真正請(qǐng)求開(kāi)始
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
其中比較關(guān)鍵的是這兩句:
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
第一句將這次請(qǐng)求加入到分發(fā)器的管理之中,分發(fā)器即Dispatcher類,這個(gè)類中有幾個(gè)保存請(qǐng)求的隊(duì)列,我們發(fā)出的每個(gè)請(qǐng)求都會(huì)添加到相應(yīng)的隊(duì)列,我們可以在請(qǐng)求流程中對(duì)每個(gè)請(qǐng)求進(jìn)行狀態(tài)查詢或取消等操作。這個(gè)類就介紹這么多吧,這個(gè)類會(huì)在后續(xù)文章詳細(xì)介紹。
第二句是真正的發(fā)起請(qǐng)求,我們看到調(diào)用了getResponseWithInterceptorChain方法,返回值是Response,說(shuō)明調(diào)用完這個(gè)方法,我們獲得了服務(wù)器發(fā)回的請(qǐng)求結(jié)果。下面詳細(xì)介紹這個(gè)方法。
getResponseWithInterceptorChain方法
方法源碼:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest, this, eventListener);
return chain.proceed(originalRequest);
}
}
從源碼看,這個(gè)方法很簡(jiǎn)單,就是在一個(gè)列表里添加一系列的攔截器(xxxInterceptor),然后創(chuàng)建了一個(gè)RealInterceptorChain對(duì)象,并調(diào)用其proceed方法,整個(gè)方法就走完了。但這個(gè)方法在整個(gè)請(qǐng)求流程中是非常重要的,而且這里還涉及一個(gè)責(zé)任鏈模式。
先說(shuō)一下責(zé)任鏈模式,GOF是這樣定義的:
使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接受者之間的耦合關(guān)系。將這個(gè)對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理他為止。

可以簡(jiǎn)單理解為,當(dāng)有一個(gè)請(qǐng)求需要處理,這時(shí)候有一條處理鏈,鏈上每個(gè)環(huán)都有可能處理這個(gè)請(qǐng)求,但是最終是哪些環(huán)參與了處理,是不一定的,只知道最終這個(gè)請(qǐng)求會(huì)被處理。因?yàn)樽罱K會(huì)被哪些環(huán)節(jié)處理以及順序是怎樣的都不一定,這樣動(dòng)態(tài)性很強(qiáng)。
對(duì)應(yīng)到OkHttp,我們發(fā)出一個(gè)請(qǐng)求,這個(gè)請(qǐng)求也會(huì)經(jīng)歷一系列的處理,上面代碼中添加的每個(gè)攔截器都有可能進(jìn)行處理