OkHttpClient
學(xué)習(xí)和使用
先通過(guò)一個(gè)非常簡(jiǎn)單的例子來(lái)看怎樣使用OKHttpClient
發(fā)送一個(gè)請(qǐng)求,然后根據(jù)這個(gè)簡(jiǎn)單例子來(lái)詳細(xì)的分析每個(gè)步驟拾给。
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request request = new Request.Builder().url("http://www.baidu.com").build();
Response response = client.newCall(request).execute();
ResponseBody responseBody = response.body();
這是一個(gè)通過(guò)OkHttpClient
發(fā)送一個(gè)簡(jiǎn)單的get
請(qǐng)求百度首頁(yè)的過(guò)程祥得。
- 創(chuàng)建一個(gè)
OkHttpClient
實(shí)例 - 創(chuàng)建一個(gè)
Request
實(shí)例 - 使用
OkHttpClient
創(chuàng)建一個(gè)Call
并執(zhí)行execute()
方法臼予,得到一個(gè)Response
對(duì)象。 - 對(duì)
Response
進(jìn)行相關(guān)操作啃沪。
以上就是整個(gè)簡(jiǎn)單HTTP請(qǐng)求的發(fā)送和接收過(guò)程。
OkHttpClient
實(shí)現(xiàn)了Cloneable
和Call.Factory
接口窄锅,Cloneable
接口表示okhttpclient
支持Object的clone方法创千。Call.Factory
接口是通過(guò)Request
創(chuàng)建一個(gè)Call
。同時(shí)也要實(shí)現(xiàn)Call.Factory
的newCall
方法入偷。
OkHttpClient
通過(guò)內(nèi)部的Builder類來(lái)創(chuàng)建追驴。生成器模式,new OkHttpClient(){ this(new Builder())}
或者new OkHttpClient.Builder().build()
.創(chuàng)建OkHttpClient
的方式比較多疏之,這樣都是使用默認(rèn)的OkHttpClient
的配置殿雪。
相關(guān)可以配置的和Client相關(guān)的還有
private static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1);
//默認(rèn)支持的協(xié)議
private static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT);
//使用https的版本和密碼套件
final Dispatcher dispatcher;//調(diào)度,異步請(qǐng)求
final Proxy proxy;//代理 java.net
final List<Protocol> protocols;
final List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors;//攔截器
final List<Interceptor> networkInterceptors;//網(wǎng)絡(luò)攔截器
final ProxySelector proxySelector;//代理選擇器
final CookieJar cookieJar;//http cookies 管理方案和 持久化
final Cache cache;//緩存
final InternalCache internalCache;//內(nèi)部緩存
final SocketFactory socketFactory;//socket 工廠 java.net
final SSLSocketFactory sslSocketFactory; //SSLSocket 工廠 java.net.ssl
final CertificateChainCleaner certificateChainCleaner;//證書方案
final HostnameVerifier hostnameVerifier;//hostName 校驗(yàn) OkHostnameVerifier
final CertificatePinner certificatePinner;//固定的證書
final Authenticator proxyAuthenticator;//代理的身份認(rèn)證
final Authenticator authenticator;// web的身份認(rèn)證
final ConnectionPool connectionPool;//連接池
final Dns dns;//DNS
final boolean followSslRedirects;//是否 執(zhí)行 ssl redirect
final boolean followRedirects;//是否執(zhí)行 redirect
final boolean retryOnConnectionFailure; //連接失敗后是否重試
final int connectTimeout;//連接超時(shí)時(shí)間
final int readTimeout;// 讀取超時(shí)
final int writeTimeout;// 寫入超時(shí)
Request
和Client一樣也是使用生成器模式完成的锋爪。
Request
中包含了
private final HttpUrl url;
private final String method;
private final Headers headers;
private final RequestBody body;
private final Object tag;
private volatile CacheControl cacheControl; // Lazily initialized.
Request
中包含的內(nèi)容都是比較清晰的丙曙,一個(gè)是HttpUrl
對(duì)象。主要內(nèi)容就是請(qǐng)求地址其骄,實(shí)例化的時(shí)候可以指定亏镰,協(xié)議,端口等拯爽。method就是指請(qǐng)求方法索抓,Headers
是請(qǐng)求頭的封裝。RequestBody
就是請(qǐng)求主體毯炮。
HttpUrl
的使用
HttpUrl url = new HttpUrl.Builder()
.scheme("https")
.host("www.baidu.com")
.addPathSegment("s")
.addQueryParameter("wd", "dota2")
.build();
System.out.println(url);
// https://www.baidu.com/s?wd=dota2
得到了一個(gè)HttpUrl
逼肯。還有很多其他的方法:
queryParameterName()
和queryParameterValue
獲取get請(qǐng)求參數(shù) 等。
RequestBody
是一個(gè)抽象類桃煎。還有兩個(gè)子類FormBody
和MultipartBody
篮幢。主要差別在于MediaType
.
回到例子中的Request
對(duì)象,使用了默認(rèn)的Request.Builder()
來(lái)構(gòu)建为迈。默認(rèn)的是get方法洲拇,默認(rèn)的Header.Builder
。tag默認(rèn)是自身曲尸。
OkHttpClient
實(shí)現(xiàn)了Call.Factory
接口赋续,創(chuàng)建一個(gè)Call
。
public Call newCall(Request request) {
return new RealCall(this, request);
}
實(shí)際上接下來(lái)的工作都是由RealCall
在完成的另患。
根據(jù)client和request創(chuàng)建一個(gè)RealCall實(shí)例纽乱,client被final修飾。默認(rèn)會(huì)加上RetryAndFollowUpInterceptor
參數(shù)昆箕。
protected RealCall(OkHttpClient client, Request originalRequest) {
this.client = client;
this.originalRequest = originalRequest;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
}
然后就是execute()
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
- 檢查這個(gè)Call是否被執(zhí)行過(guò)
- 利用
client.dispatcher.execute(this)
來(lái)完成實(shí)際的請(qǐng)求過(guò)程鸦列。Dispatcher
在client文檔中的表示的是異步請(qǐng)求的調(diào)度租冠。實(shí)際上同步請(qǐng)求也是通過(guò)他們來(lái)調(diào)度完成的 -
Reqsponse
是通過(guò)getResponseWithInterceptorChain()
方法獲得的。從方法名可知薯嗤,會(huì)通過(guò)一系列的攔截器顽爹。 - 最后通知
dispatcher
執(zhí)行完成。
具體的Dispatcher
稍后看骆姐,先關(guān)注發(fā)送請(qǐng)求解析返回結(jié)果的getResponseWithInterceptorChain()
镜粤。
private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
這個(gè)方法把網(wǎng)絡(luò)請(qǐng)求,重試玻褪,緩存肉渴,壓縮等操作都統(tǒng)一成一個(gè)個(gè)Interceptor。形成一個(gè)Interceptor.Chain
带射,最后完成一次請(qǐng)求的過(guò)程同规。
通過(guò)getResponseWithInterceptorChain()
可以看出Interceptor.Chain
的組成部分:
-
client.interceptors
構(gòu)造client
的時(shí)候設(shè)置的Interceptors
-
retryAndFollowUpInterceptor
負(fù)責(zé)失敗重試和重定向。this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
在構(gòu)造RealCall
時(shí)創(chuàng)建窟社。 - 橋接券勺,將請(qǐng)求轉(zhuǎn)換成發(fā)送到服務(wù)器的請(qǐng)求、通過(guò)網(wǎng)絡(luò)響應(yīng)構(gòu)造一個(gè)服務(wù)器的返回響應(yīng)d的
BridgeInterceptor
灿里。 - 讀取緩存返回朱灿,更新緩存的
CacheInterceptor
。 - 和服務(wù)器創(chuàng)建連接的
ConnectInterceptor
钠四。 -
CallServerInterceptor
makes a network call to the server 最后一個(gè)Interceptor.
然后創(chuàng)建一個(gè)Interceptor.Chain
實(shí)例盗扒,執(zhí)行proceed方法。得到Response
.