OKHttp3初始化與配置
OKhttp在使用時,最基本的組成部分是OkHttpClient、Request、Call和Response,需要進行初始化的主要是OkHttpClient和Request。
OKHttpClient
一般情況下,全局只需一個OkHttpClient實例(強烈建議),便可以滿足整個應用的Http請求,其主要是由OkHttpClient.Builder的建造者模式來進行配置和初始化的,如可創建一個用於普通http請求的公用OkHttpClient實例:
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
也可以創建定製化的實例:
OkHttpClient customClient = okHttpClient.newBuilder()
.readTimeout(10000, TimeUnit.MILLISECONDS)
.build();
定製化的OkHttpClient與原實例共享連接池、線程池和公共配置項。OkHttpClient的配置項位於build方法前。
常用配置項
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS) //設置連接超時
.readTimeout(60, TimeUnit.SECONDS) //設置讀超時
.writeTimeout(60, TimeUnit.SECONDS) //設置寫超時
.retryOnConnectionFailure(true) //是否自動重連
.build();
Https配置
對於https(此處可簡單複習一下https簡單原理),需要配置sslSocketFactory,一般如需忽略所有證書的話,可以這樣配置:
client = new OkHttpClient.Builder()
// 設置https配置,此處忽略了所有證書
.sslSocketFactory(createEasySSLContext().getSocketFactory(), new EasyX509TrustManager(null))
.build();
private static SSLContext createEasySSLContext() throws IOException {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
return context;
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
public class EasyX509TrustManager implements X509TrustManager {
private X509TrustManager standardTrustManager = null;
/**
* Constructor for EasyX509TrustManager.
*/
public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException,
KeyStoreException {
super();
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory
.getDefaultAlgorithm());
factory.init(keystore);
TrustManager[] trustmanagers = factory.getTrustManagers();
if (trustmanagers.length == 0) {
throw new NoSuchAlgorithmException("no trust manager found");
}
this.standardTrustManager = (X509TrustManager)trustmanagers[0];
}
/**
* @see X509TrustManager#checkClientTrusted(X509Certificate[],
* String authType)
*/
public void checkClientTrusted(X509Certificate[] certificates, String authType)
throws CertificateException {
standardTrustManager.checkClientTrusted(certificates, authType);
}
/**
* @see X509TrustManager#checkServerTrusted(X509Certificate[],
* String authType)
*/
public void checkServerTrusted(X509Certificate[] certificates, String authType)
throws CertificateException {
if ((certificates != null) && (certificates.length == 1)) {
certificates[0].checkValidity();
} else {
standardTrustManager.checkServerTrusted(certificates, authType);
}
}
/**
* @see X509TrustManager#getAcceptedIssuers()
*/
public X509Certificate[] getAcceptedIssuers() {
return this.standardTrustManager.getAcceptedIssuers();
}
}
此外還可以使用以下代碼忽略本地校驗url正確性:
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}) // 驗證服務器的證書域名。在https握手期間,如果 URL 的主機名和服務器的標識主機名不匹配,則驗證機制可以回調此接口的實現程序來確定是否應該允許此連接
攔截器
攔截器有兩種,應用攔截器和網絡攔截器:
詳細的攔截器分析說明可見此處,我們最常使用的攔截器就是網絡日誌打印功能了:
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Log.d("intercept", "接口地址:" + request.url()
+ "\r\n接口參數(這裏一般不直接toString,body裏的是stream):" + request.body().toString());
}
return chain.proceed(chain.request());
}
}) // 日誌記錄
其他與https相關的配置項(以下可忽略,一般不用設置,純當筆記,摘自此處):
.certificatePinner(new CertificatePinner.Builder()
.add("test1.com", "sha1/sdfsdsdsdsdsdsdsdsdsdsdds=")
.add("test2.com", "sha1/sdsdsdsdsdsdsdsdsdssdssds=")
.build()) // 添加證書,一般不要設置
添加受信證書,最好不要去設置,詳見此處。
.connectionSpecs(...) // 設置連接的規格、TLS版本和密碼套件等
其他設置
.socketFactory(new SocketFactory() {...}) // 使用定製的用於http請求的套接字
.authenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
...
}
}) // 添加授權證書
通過Authenticator類,可以響應來自遠程或者代理服務器的授權驗證,通常情況會返回一個授權頭以做驗證;亦或是返回空表示拒絕驗證。簡單來說,你要訪問一個服務,但是你要對方的驗證。通過Authenticator類來代理一個認證請求,並使用Credentials.basic()來構造一個證書。
.cache(new Cache(new File("cache.tmp"), 10 * 1024 * 1024)) // 10M緩存
.connectionPool(new ConnectionPool(5, 6, TimeUnit.MINUTES))
// 定義連接池,最多有五個空閒連接,每個空閒連接最多保持6分鐘
OkHttp使用共享連接池,默認爲5個5分鐘空閒的連接池。
.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
// response時保存cookie
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
// request發送前,將cookie加到request中
return ...;
}
}) // cookie保存和使用
若需要持久化cookie,此篇文章可以借鑑。
.dispatcher(new Dispatcher(new ThreadPoolExecutor(...)))
// 指定分發器,即異步執行http請求時的線程池,http響應的回調也是在此線程池的線程中執行
.dispatcher(new Dispatcher(new ThreadPoolExecutor(...)))
// 指定分發器,即異步執行http請求時的線程池,http響應的回調也是在此線程池的線程中執行
.followRedirects(true) // 允許http重定向
.followSslRedirects(false) // 截斷https的重定向
這兩個都是設置是否進行鏈接重定向的。設置爲false時,可以截斷重定向。在一些無限循環重定向的鏈接情況下,通過截斷重定向,並在Call的onResponse中自行處理重定向,可以解決此問題。
.pingInterval(30, TimeUnit.SECONDS) // 設置ping檢測網絡連通性的間隔。默認爲0
.protocols() // 設置使用的協議,目前支持http1.1和http2,不能包含空和http1.0。一般不會設置
.proxy(...) // 設置單個代理
.proxyAuthenticator(...) // 設置代理驗證
.proxySelector(...) // 爲不同的鏈接設置不同的代理
Request
Request也如okhttpclient一樣使用構造者模式生成、複用屬性,其主要由四部分組成:
Method就是http支持的head、post、get、delete、put、patch:
Request request = new Request.Builder()
.head()
.post(requestBody)
.get()
.delete().delete(requestBody)
.put(requestBody)
.patch(requestBody)
.method(“post”, requestBody)
Body主要用於post、delete、put、patch時的內容,如提交json字符串:
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
RequestBody rb = RequestBody.create(JSON, jsonString);
Url即指定鏈接:
.url("http://www.baidu.com")
.url(HttpUrl.parse("http://www.baidu.com"))
.url(new HttpUrl.Builder(). ... .build());
Header可以設置請求的頭:
.addHeader("sd", "dsds") // 添加頭部,不會覆蓋舊值
.header("fd", "sdasd") // 替換相同name的值
.removeHeader("fd") // 刪除頭部
其他常用設置有:
緩存,針對單個請求:
final CacheControl.Builder builder = new CacheControl.Builder();
builder.noCache(); // 不使用緩存,全部走網絡
builder.noStore(); // 不使用緩存,也不存儲緩存
builder.onlyIfCached(); // 只使用緩存
builder.noTransform(); // 禁止轉碼
builder.maxAge(10, TimeUnit.SECONDS); // 能接收10秒內的緩存
builder.maxStale(10, TimeUnit.SECONDS);
// 指示客戶機可以接收超出超時期間的響應消息,即過期後的10秒內緩存可以繼續使用,cache的響應頭部會有提示
builder.minFresh(10, TimeUnit.SECONDS);
// 至少在10秒內,緩存要保持更新
CacheControl cache = builder.build();
xxxRequestBuilder.cacheControl(cache)
.tag("asdsad") // 設置tag,可以用於標記每個request等
參考資料
OKHttp3.0的日常及入門
OkHttp3之Cookies管理及持久化
Class CertificatePinner
square/okhttp的https配置
OkHttp之攔截器
HTTPS工作原理和TCP握手機制