OkHttp是一款網(wǎng)絡(luò)請求框架浑塞,【OkHttp傳送門】,為了在開發(fā)中使用的更加得心應(yīng)手季惩,必然的要去探究其源碼录粱,分析其中的工作原理腻格,而且還能學(xué)習(xí)框架的設(shè)計(jì)思想画拾。文章主要對OkHttp整體的工作流程進(jìn)行分析,所以一些操作方法并沒有涉及菜职,讀者可以通過傳送門閱讀文檔自行實(shí)踐青抛。在分析之前,先看一張整體的流程圖(本文內(nèi)容會根據(jù)圖的流程展開):
OkHttp請求網(wǎng)絡(luò)的簡單示例
private static final String URL_CONTENT = "https://www.baidu.com/";
public static void doOkHttp() {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.retryOnConnectionFailure(true) //連接失敗后進(jìn)行重連
.build();
final Request request = new Request.Builder()
.url(URL_CONTENT)
.build();
//異步方式請求網(wǎng)絡(luò)
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//請求失敗
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//請求成功,對response進(jìn)行處理
}
});
}
上面的代碼酬核,首先創(chuàng)建一個(gè)okHttpClient對象蜜另,調(diào)用newCall()并且request作為參數(shù)傳入,然后執(zhí)行enqueue()嫡意,并且new一個(gè)Callback举瑰,請求結(jié)果的回調(diào),這個(gè)過程是異步的蔬螟。
//execute()是同步的方式請求網(wǎng)絡(luò)此迅,會阻塞UI線程,所以一般情況都是通過異步的方式請求網(wǎng)絡(luò)
okHttpClient.newCall(request).execute();
1旧巾、OkHttpClient的build()過程耸序。
public Builder() {
dispatcher = new Dispatcher(); //異步請求調(diào)度器
protocols = DEFAULT_PROTOCOLS;//請求協(xié)議集合,默認(rèn)為http/1.1和Http/2
connectionSpecs = DEFAULT_CONNECTION_SPECS;//連接規(guī)格
eventListenerFactory = EventListener.factory(EventListener.NONE);//事件監(jiān)聽器
proxySelector = ProxySelector.getDefault();//代理選擇器
cookieJar = CookieJar.NO_COOKIES;//http cookies 提供持久化策略
socketFactory = SocketFactory.getDefault(); //socket工廠類
hostnameVerifier = OkHostnameVerifier.INSTANCE;//對host基本接口的驗(yàn)證
certificatePinner = CertificatePinner.DEFAULT; //約束的信任證書
proxyAuthenticator = Authenticator.NONE;//代理身份認(rèn)證
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();//連接復(fù)用池
dns = Dns.SYSTEM;//默認(rèn)使用系統(tǒng)的dns
followSslRedirects = true; //遵循SSL重定向
followRedirects = true;//普通重定向
retryOnConnectionFailure = true;//連接失敗后進(jìn)行重新連接
connectTimeout = 10_000;//連接超時(shí)時(shí)間
readTimeout = 10_000;//讀取數(shù)據(jù)超時(shí)時(shí)間
writeTimeout = 10_000;//發(fā)送數(shù)據(jù)超時(shí)時(shí)間
pingInterval = 0;//時(shí)間間隔
}
public OkHttpClient build() {
return new OkHttpClient(this);
}
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);//網(wǎng)絡(luò)攔截器
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;//創(chuàng)建OkHttpClient對象時(shí)的自定義緩存
this.internalCache = builder.internalCache;//內(nèi)部緩存
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);
}
}
通過建造者模式創(chuàng)建OkHttpClient對象鲁猩,并且配置各種參數(shù)坎怪。
2、Request的Builder()的過程
public Builder() {
this.method = "GET"; //請求方法廓握,默認(rèn)GET
this.headers = new Headers.Builder();//創(chuàng)建請求頭
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
Request(Builder builder) {
this.url = builder.url; //請求url
this.method = builder.method;//請求方法
this.headers = builder.headers.build();//請求頭
this.body = builder.body;//請求體
this.tag = builder.tag != null ? builder.tag : this;
}
Request也是以建造者模式創(chuàng)建對象搅窿,配置參數(shù)。關(guān)于HTTP報(bào)文結(jié)構(gòu)圖(左圖對應(yīng)Request隙券,右圖對應(yīng)Response):
3戈钢、okHttpClient.newCall()
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
//RealCall # newRealCall
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;
}
調(diào)用newCall()實(shí)際返回的是一個(gè)RealCall(繼承自Call)對象。RealCall內(nèi)部封裝了網(wǎng)絡(luò)請求和請求結(jié)果回調(diào)是尔。那么殉了,上面的異步請求實(shí)際調(diào)用的是RealCall的enqueue()方法。
4拟枚、RealCall # enqueue()
public void enqueue(Callback responseCallback) {
synchronized (this) {
//若任務(wù)已經(jīng)執(zhí)行薪铜,則拋出IllegalStateException
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//跟蹤調(diào)用堆棧
captureCallStackTrace();
//監(jiān)聽開始事件
eventListener.callStart(this);
// 1
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
上面代碼的核心是注釋1處,client.dispatcher()返回一個(gè)Dispatcher對象恩溅,異步請求調(diào)度器隔箍,里面會對任務(wù)進(jìn)行分辨,是立刻執(zhí)行還是放入等待隊(duì)列脚乡。AsyncCall繼承NamedRunnable(實(shí)現(xiàn)了Runnable接口)類蜒滩,接著進(jìn)入Dispatcher的enqueue()方法:
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
從代碼可以發(fā)現(xiàn)滨达,Dispatcher的enqueue()是一個(gè)同步方法,maxRequests是最大請求數(shù)(值為64)俯艰,maxRequestsPerHost是Host最大請求數(shù)據(jù)(值為5)捡遍,當(dāng)滿足這兩個(gè)條件時(shí),把任務(wù)添加到執(zhí)行隊(duì)列runningAsyncCalls竹握,立刻執(zhí)行画株,否則加入等待隊(duì)列readyAsyncCalls,等待異步調(diào)用啦辐。executorService()內(nèi)部創(chuàng)建了一個(gè)執(zhí)行任務(wù)的線程池谓传,并且返回一個(gè)執(zhí)行對象ExecutorService。
executorService()的內(nèi)部實(shí)現(xiàn):
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
以單例模式中的懶漢模式創(chuàng)建了一個(gè)線程池芹关。其實(shí)上面創(chuàng)建的線程池和我們直接用Executors的newCachedThreadPool()創(chuàng)建是類似的续挟,核心線程數(shù)為0,線程空閑時(shí)的超時(shí)時(shí)間60s侥衬,直接提交策略诗祸。關(guān)于線程池的分析,可以閱讀【探索Java 線程池】這篇文章浇冰。在這里贬媒,往線程池中添加的任務(wù)對象是AsyncCall,那么看看AsyncCall的內(nèi)部實(shí)現(xiàn):
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override
protected void execute() {
boolean signalledCallback = false;
try {
//核心請求
Response response = getResponseWithInterceptorChain();
//根據(jù)是否取消RetryAndFollowUpInterceptor,分別回調(diào)onFailure或onResponse
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//請求完畢肘习,移除runningAsyncCalls中當(dāng)前執(zhí)行的Call际乘。
//并且查找等待隊(duì)列readyAsyncCalls是否存在任務(wù),存在漂佩,則添加執(zhí)行隊(duì)列runningAsyncCalls脖含,然后執(zhí)行任務(wù)
//如果runningAsyncCalls不存在任務(wù),且idleCallback不為null投蝉,則啟動空閑狀態(tài)Runnable
client.dispatcher().finished(this);
}
}
}
NamedRunnable實(shí)現(xiàn)了Runnable接口养葵,在其run()方法內(nèi)部調(diào)用了execute()方法,這里運(yùn)用了設(shè)計(jì)模式中的模板模式瘩缆,那么关拒,這里就把任務(wù)交給了AsyncCall的execute()方法。通過代碼的注釋可以知道庸娱,把請求交由了getResponseWithInterceptorChain()方法着绊,這個(gè)方法直譯過來意思就是:用攔截器鏈獲取響應(yīng)報(bào)文。而方法內(nèi)部也正運(yùn)用了設(shè)計(jì)模式中的責(zé)任鏈模式熟尉。
模板模式
優(yōu)點(diǎn):封裝不變部分归露,擴(kuò)展可變部分;提取公共部分代碼斤儿,便于維護(hù)剧包。
缺點(diǎn):在代碼閱讀方面可能會帶來相對的難度恐锦。責(zé)任鏈模式
優(yōu)點(diǎn):對請求者和處理者關(guān)系解耦,提高了代碼靈活性疆液。
缺點(diǎn):如果處理者太多一铅,過多的遍歷會導(dǎo)致性能降低。
回到OkHttp的請求流程枚粘,上面已經(jīng)把任務(wù)交由了getResponseWithInterceptorChain()方法馅闽,那么飘蚯,看下其內(nèi)部實(shí)現(xiàn)馍迄。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//初始化OkHttpClient對象時(shí)添加的自定義interceptors
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) {
//添加用戶自定義的networkInterceptors
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);
}
getResponseWithInterceptorChain()內(nèi)部添加各種攔截器,利用RealInterceptorChain將已有的攔截器進(jìn)行串聯(lián)局骤,然后proceed()開始遍歷攔截器攀圈。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
... ....//省略部分代碼
// Call the next interceptor in the chain.
//遍歷攔截器鏈,index代表責(zé)任鏈中攔截器的下標(biāo)峦甩,初始值為0
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
... ...//省略部分代碼
return response;
}
5赘来、分析各個(gè)攔截器的作用
- RetryAndFollowUpInterceptor:在連接失敗后進(jìn)行重新連接,必要時(shí)進(jìn)行重定向凯傲,如果調(diào)用被取消犬辰,可能會拋出IOException
- BridgeInterceptor:構(gòu)建訪問網(wǎng)絡(luò)的橋梁,首先冰单,將用戶請求轉(zhuǎn)換成網(wǎng)絡(luò)請求幌缝,然后訪問網(wǎng)絡(luò),最后將網(wǎng)絡(luò)響應(yīng)轉(zhuǎn)換成用戶響應(yīng)诫欠。
- CacheInterceptor:緩存攔截器涵卵,從緩存中獲取服務(wù)器請求,或者把服務(wù)器響應(yīng)寫入緩存中荒叼。
- ConnectInterceptor:打開一個(gè)連接轿偎,去連接目標(biāo)服務(wù)器。
- CallServerInterceptor:攔截器鏈中的最后一個(gè)鏈點(diǎn)被廓,通過網(wǎng)絡(luò)請求服務(wù)器坏晦。
鏈?zhǔn)綀?zhí)行流程:
5.1、RetryAndFollowUpInterceptor # intercept()
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
//用于分配一個(gè)到服務(wù)器特定的HttpStream嫁乘,內(nèi)部封裝了ConnectionPool連接池昆婿,管理Http的連接
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
int followUpCount = 0;
Response priorResponse = null;
//開啟輪詢
while (true) {
//若已取消連接,釋放資源
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
//調(diào)用下一個(gè)攔截器
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getLastConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
// Attach the prior response if it exists. Such responses never have a body.
//檢測前一個(gè)Response
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Request followUp = followUpRequest(response, streamAllocation.route());
//followUp為null亦渗,表示不要重定向挖诸,釋放資源并且返回response
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
return response;
}
//關(guān)閉response的body
closeQuietly(response.body());
//最大重定向次數(shù)20
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
//如果是不可重復(fù)的請求體,拋出異常
if (followUp.body() instanceof UnrepeatableRequestBody) {
streamAllocation.release();
throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
}
//檢測地址是否相同法精,釋放舊連接多律,重新創(chuàng)建一個(gè)新的連接
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(followUp.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
priorResponse = response;
}
}
5.2痴突、BridgeInterceptor # intercept()
public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
//將用戶的Request構(gòu)造成服務(wù)器的Request
RequestBody body = userRequest.body();
if (body != null) { //請求體存在,進(jìn)行轉(zhuǎn)換
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
//保持連接
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
//使用Gzip壓縮
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
//設(shè)置cookies
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
//傳入已構(gòu)造好的服務(wù)器Request狼荞,調(diào)用下一個(gè)攔截器辽装,獲取服務(wù)器的networkResponse
Response networkResponse = chain.proceed(requestBuilder.build());
//保存networkResponse的cookie
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
//后續(xù)則是把networkResponse構(gòu)造成用戶的response
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
return responseBuilder.build();
}
5.3、CacheInterceptor # intercept()
public Response intercept(Chain chain) throws IOException {
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
//獲取當(dāng)前時(shí)間
long now = System.currentTimeMillis();
//獲取緩存策略
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
//從緩存中追蹤Response
if (cache != null) {
cache.trackResponse(strategy);
}
//如果緩存不適用相味,則關(guān)閉
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body());
}
// 如果網(wǎng)絡(luò)被禁止拾积,且緩存為空,則返回失敗
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
// 不需要網(wǎng)絡(luò)時(shí)丰涉,從緩存中獲取
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
//調(diào)用下一個(gè)攔截者拓巧,從網(wǎng)絡(luò)獲取Response
networkResponse = chain.proceed(networkRequest);
} finally {
// 關(guān)閉body,防止內(nèi)存泄露
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// 如果緩存中存在Response一死,同時(shí)檢測networkResponse是否被修改
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
//更新緩存中的數(shù)據(jù)至最新
cache.trackConditionalCacheHit();
cache.update(cacheResponse, response);
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
//構(gòu)建response
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
//把之前未緩存的添加至緩存中
if (cache != null) {
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}
5.4肛度、ConnectInterceptor # intercept()
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
//獲取httpCodec 對象,HttpCodec的實(shí)現(xiàn)類有Http1Codec和Http2Codec
//分別對應(yīng)Http1.1和Http2
//HttpCodec主要是對Http請求和Http響應(yīng)進(jìn)行編解碼
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
//調(diào)用下一個(gè)攔截器
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
StreamAllocation的newStream()方法內(nèi)部實(shí)現(xiàn)
public HttpCodec newStream(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
int connectTimeout = chain.connectTimeoutMillis();
int readTimeout = chain.readTimeoutMillis();
int writeTimeout = chain.writeTimeoutMillis();
int pingIntervalMillis = client.pingIntervalMillis();
boolean connectionRetryEnabled = client.retryOnConnectionFailure();
try {
//尋找一個(gè)可用連接
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
//根據(jù)具體的resultConnection 創(chuàng)建resultCodec對象
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
5.5投慈、CallServerInterceptor # intercept()
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;
//檢測是否有body的請求方法
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
//如果請求頭是"100-continue"承耿,等待服務(wù)器的響應(yīng)
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();
//將請求體轉(zhuǎn)換成sink,并封裝在CountingSink 內(nèi)部
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();
//從httpCodec中獲取響應(yīng)頭
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
//構(gòu)建response
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
//如果服務(wù)器返回的狀態(tài)碼是100伪煤,再次嘗試讀取具體的response
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);
//如果是WebSocket加袋,并且返回狀態(tài)碼為101,表示響應(yīng)body為空
if (forWebSocket && code == 101) {
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
//讀取body
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
//如果響應(yīng)頭部是"close"抱既,關(guān)閉流
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
//協(xié)議異常
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
到這里职烧,OkHttp的執(zhí)行流程就分析完畢了。
關(guān)于OkHttp3系列的其它文章:
OkHttp3 源碼解析 連接池的復(fù)用
OkHttp3源碼解析內(nèi)部緩存