在Java Web中,我們一般使用HttpComponent發起網絡請求。HttpComponent獲取分爲兩步:
1、獲取到HttpClient
2、發起請求
今天來看一下如何配置HttpClient來達到我們想要的效果
一、連接池與設置HttpClient連接池數
HTTPComponent中有連接池的概念,比如我們有一個連接 連接了www.baidu.com ,那麼當這個連接使用完畢後,下一個線程想要請求 www.baidu.com ,就可以直接使用這個連接,這是連接池的概念,那麼我們如何去設置連接池的大小呢?
HTTPComponent中有兩個連接管理器,一個是 BasicHttpClientConnectionManager ,一個是PoolingHttpClientConnectionManager。 BasicHttpClientConnectionManager 同一時間只能有一個連接,所以我們基本上不用,而PoolingHttpClientConnectionManager則爲幾乎所有人使用的連接管理器,也就是我們所說的連接池。
設置poolSize:
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
// MaxPerRoute 設置一路有多大的緩存,比如訪問 www.baidu.com 的爲一路,那麼訪問 www.baidu.com 的連接最大限制到多少,比如是100,那麼最多限制100個連接 www.baidu.com 的
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
// 最多對外多少個連接,比如爲 200 ,則爲最大對外200個連接
poolingHttpClientConnectionManager.setMaxTotal(200);
注意連接不像連接數據庫那樣永遠只有一種連接,HttpComponent中不同的域名是不同路的連接,連接成功後不能共用,所以 setDefaultMaxPerRoute 是設置相同路的最大連接數,setMaxTotal是設置最大的所有連接數。
二、如何設置默認的 connectionRequestTimeOut、connectionTimeOut、readTimeOut?
RequestConfig requestConfig = RequestConfig.custom().
setConnectionRequestTimeout(1000).
setConnectTimeout(1000).
setSocketTimeout(5000)
.build();
上述爲設置超時時間,其中
1、connectionRequestTimeOut 爲獲取到 連接請求 的超時時間(也就是說獲取到了連接請求 之後才能進行連接,否則需要等待 )。
2、ConnectTimeout 爲連接的超時時間。
3、SocketTimeout爲連接成功後 客戶端和服務進行數據交互的超時時間,是指兩者之間如果兩個數據包之間的時間大於該時間則認爲超時,而不是整個交互的整體時間,比如如果設置1秒超時,如果每隔0.8秒傳輸一次數據,傳輸10次,總共8秒,這樣是不超時的。而如果任意兩個數據包之間的時間超過了1秒,則超時。要注意SocketTimeout不是總時長,不過一般來說,我們經常會阻塞在服務端的處理過程中,服務端的返回一般在一個數據包內,就算是多個數據包,多個數據包發送也很快,所以SocketTimeOut一般可以看成是總時長。
上述爲設置默認的超時時間,下節會講到設置單次請求的超時時間。
三、設置ConnectionSocketFactory
PoolingHttpClientConnectionManager 爲 連接請求 管理器,當獲取到 連接請求 後,若此 連接請求 未與服務端連接,我們還需要進行連接,此時就用到了 ConnectionSocketFactory 。需要注意的是,HttpComponent中,HTTP的連接類默認只有一個 ,爲 PlainConnectionSocketFactory ,HTTPS的連接類默認也只有一個,爲 SSLConnectionSocketFactory 。
之所以要知道上述概念,是因爲當我們發起https請求時,若對方服務端爲自籤的證書,則會報x509錯誤,一般情況下,我們會忽略這個錯誤,下面獲取HttpClient的代碼中講到了如何忽略這個錯誤:
SSLContext sc = null;
try {
sc = SSLContext.getInstance("SSLv3");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 實現一個X509TrustManager接口,用於繞過驗證,不用修改裏面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
try {
sc.init(null, new TrustManager[]{trustManager}, null);
} catch (KeyManagementException e) {
e.printStackTrace();
}
// 設置協議http和https對應的處理socket鏈接工廠的對象
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sc))
.build();
四、獲取到HttpClient:
此爲獲取到HttpClient的正確姿勢:
public static CloseableHttpClient getHttpClient() {
SSLContext sc = null;
try {
sc = SSLContext.getInstance("SSLv3");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 實現一個X509TrustManager接口,用於繞過驗證,不用修改裏面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
try {
sc.init(null, new TrustManager[]{trustManager}, null);
} catch (KeyManagementException e) {
e.printStackTrace();
}
// 設置協議http和https對應的處理socket鏈接工廠的對象
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sc))
.build();
// 生成一個PoolingHttpClientConnectionManager
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// MaxPerRoute 設置一路有多大的緩存,比如訪問 www.baidu.com 的爲一路,那麼訪問 www.baidu.com 的連接最大限制到多少,比如是100,那麼限制最多有100個 www.baidu.com 的連接
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
// 最多對外多少個連接,比如爲 200 ,則爲最大對外200個連接
poolingHttpClientConnectionManager.setMaxTotal(200);
// 設置超時時間
RequestConfig requestConfig = RequestConfig.custom().
setConnectionRequestTimeout(1000).
setConnectTimeout(1000).
setSocketTimeout(5000)
.build();
CloseableHttpClient httpClient = HttpClientBuilder.create()
// 設置默認的config,如果請求沒有設置config的話,那麼就用這個config
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(poolingHttpClientConnectionManager)
.build();
return httpClient;
}