接上篇抽絲剝繭okhttp(三) http://www.reibang.com/p/cf59397dce1f
下面是極簡版的okhttp請求網(wǎng)絡(luò)的流程圖娶桦,之前分析過了Response、Request這兩個涉及http本身的協(xié)議的封裝汁汗。那么如何宏觀上看整個請求流程呢衷畦?
1 OkHttpClient負(fù)責(zé)把這些部件和配置裝配起來
2 用Call對象發(fā)出請求,
3 在發(fā)送和接收過程中通過很多攔截器處理知牌,
4 之后我們接得了response對象祈争,整個網(wǎng)絡(luò)請求流程完成。
一共四步角寸,聯(lián)想實際的網(wǎng)絡(luò)請求不難理解菩混。
那么這四步具體是如何實現(xiàn)的呢球匕?我們一步一步的來抽絲剝繭。
OkhttpClient
OkhttpClient充當(dāng)?shù)氖且粋€客戶端的角色照卦,負(fù)責(zé)收集請求役耕,配置信息,創(chuàng)建用于實際發(fā)出請求的Call。下面根據(jù)我們實際項目順序了解一下OkhttpClient的運行機(jī)制津辩。
1 .OkhttpClient的創(chuàng)建
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
OkhttpClient的創(chuàng)建也builder模式蚜印,但暴露給外部的是一new出來的窄赋,內(nèi)部調(diào)用第二個采用builder構(gòu)造方法柒傻。這樣做是為了初始化builder中默認(rèn)的重要參數(shù)红符,避免用戶調(diào)用的時候這么多的參數(shù)用戶很大可能上會配錯一些東西。這樣簡化了操作致开。
我們?nèi)绾伟l(fā)起請求,獲得response呢
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
OkhttpClient實現(xiàn)了Call.Factory的newCall()虹蒋,這樣為我們生產(chǎn)出來一個新的隨時可以發(fā)起網(wǎng)絡(luò)請求的Call對象;
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
可以看到他返回的是一個用RealCall從創(chuàng)建出來的而且是RealCall對象晃虫。
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
這個RealCall對象正是對網(wǎng)絡(luò)請求的真正發(fā)起者哲银,起重大作用。RealCall實現(xiàn)了Call接口草巡,我們看Call的定義。
public interface Call extends Cloneable {
//返回原始的Request
Request request();
//立即執(zhí)行網(wǎng)絡(luò)請求
Response execute() throws IOException;
//在將來的某一時刻發(fā)起請求
void enqueue(Callback responseCallback);
//判斷是否被執(zhí)行了
boolean isExecuted();
//判斷是否被取消了
boolean isCanceled();
//創(chuàng)建出來一個新的Call對象
Call clone();
interface Factory {
Call newCall(Request request);
}
}
RealCall中復(fù)寫的這些方法全權(quán)的執(zhí)行了網(wǎng)絡(luò)請求的工作。所以我們繞了這么大彎子終于看到在哪進(jìn)行的網(wǎng)絡(luò)請求了棚亩。
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
execute 和 enqueue中分別調(diào)用了
client.dispatcher().finished(this);;和 client.dispatcher().enqueue(new AsyncCall(responseCallback));
一個同步一個異步的纺阔。用dispatcher放到一個隊列中進(jìn)行分發(fā)運行质况,對于enqueue因為AsyncCall實現(xiàn)了Runnable接口结榄,在dispatcher中的的線程池運行隊列里的Runnable對象邻寿,執(zhí)行executorService().execute(call);所以最后的網(wǎng)絡(luò)請求還在這個AsyncCall對象對于runnable的實現(xiàn)中。他們共同的會調(diào)用
Response response = getResponseWithInterceptorChain();
獲得了Response對象枝秤。那么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, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
這里添加了okhttp默認(rèn)的幾個攔截器沐序,并進(jìn)入chain.proceed(originalRequest);至此進(jìn)入了一大堆攔截器各種攔截最后返回response的模式策幼,關(guān)于攔截器我們以后再說,現(xiàn)在先過唐含。經(jīng)過層層攔截器我們終于拿到了最終的響應(yīng)對象。如此推演我們可以推斷出我們真正的請求應(yīng)在最后一個攔截器中淮捆。我們看一下:就是那個CallServerInterceptor
/** This is the last interceptor in the chain. It makes a network call to the server. */
public final class CallServerInterceptor implements Interceptor {
private final boolean forWebSocket;
public CallServerInterceptor(boolean forWebSocket) {
this.forWebSocket = forWebSocket;
}
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
realChain.eventListener().requestHeadersStart(realChain.call());
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
// If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
// Continue" response before transmitting the request body. If we don't get that, return
// what we did get (such as a 4xx response) without ever transmitting the request body.
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(true);
}
if (responseBuilder == null) {
// Write the request body if the "Expect: 100-continue" expectation was met.
realChain.eventListener().requestBodyStart(realChain.call());
long contentLength = request.body().contentLength();
CountingSink requestBodyOut =
new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
realChain.eventListener()
.requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
} else if (!connection.isMultiplexed()) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
// from being reused. Otherwise we're still obligated to transmit the request body to
// leave the connection in a consistent state.
streamAllocation.noNewStreams();
}
}
httpCodec.finishRequest();
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
responseBuilder = httpCodec.readResponseHeaders(false);
response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
realChain.eventListener()
.responseHeadersEnd(realChain.call(), response);
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
static final class CountingSink extends ForwardingSink {
long successfulCount;
CountingSink(Sink delegate) {
super(delegate);
}
@Override public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
successfulCount += byteCount;
}
}
}
果不其然 我們看眼注釋就知道了:This is the last interceptor in the chain. It makes a network call to the server. */
也驗證了我們之前的猜測涩笤。intercept方法中確確實實的執(zhí)行了網(wǎng)絡(luò)請求,但在okhttp3.internal包中的類涉及底層更多一些恩沽,本人目前精力有限罗心,只能分析到這層,但目前看來對于輪子我們了解了差不多了飒箭,大件都拆了,小件拆了也不一定能用的到盈匾,所以就到這層削饵。
這里返回的 response就是我最終可以使用的response了窿撬。
這個response我們一層一層返回上層 我們在哪能拿到還記得么?那就是execute()同步請求中直接返回严里,enqueue中的callback中
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
public interface Callback {
/**
* Called when the request could not be executed due to cancellation, a connectivity problem or
* timeout. Because networks can fail during an exchange, it is possible that the remote server
* accepted the request before the failure.
*/
void onFailure(Call call, IOException e);
/**
* Called when the HTTP response was successfully returned by the remote server. The callback may
* proceed to read the response body with {@link Response#body}. The response is still live until
* its response body is {@linkplain ResponseBody closed}. The recipient of the callback may
* consume the response body on another thread.
*
* <p>Note that transport-layer success (receiving a HTTP response code, headers and body) does
* not necessarily indicate application-layer success: {@code response} may still indicate an
* unhappy HTTP response code like 404 or 500.
*/
void onResponse(Call call, Response response) throws IOException;
}
這樣開發(fā)者朋友們就拿到可請求之后的Response了迷帜。這樣我們終于看到okhttp官網(wǎng)上的那幾段示例代碼都做了什么事情了;我順便貼出來锦针,順便也回味一下:
Examples
GET A URL
This program downloads a URL and print its contents as a string. Full source.
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
POST TO A SERVER
This program posts data to a service. Full source.
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
總結(jié)
總結(jié)一下盾碗,整個網(wǎng)絡(luò)請求過程中okhttpclient的角色就是準(zhǔn)備材料耗美,Call對象負(fù)責(zé)發(fā)起,但發(fā)起的意義在于把請求放到隊列里執(zhí)行蛇摸,在此之后一直到最后請求成功這中間又精力了若干的攔截器。正是這些攔截器實現(xiàn)了更多更具有拓展性的工作抠藕,默認(rèn)添加進(jìn)去的攔截器如下:
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添加到這里面實現(xiàn)各式各樣的功能需求村刨,所以interceptor的設(shè)計師okhttp的絕妙之筆琅关。關(guān)于interceptor我們后續(xù)有機(jī)會再行解析。