? ? ?版權聲明:本文為博主原創文章,未經博主允許不得轉載。如需轉載請聲明:【轉自 http://blog.csdn.net/xiaoxian8023 】
? ? ?上一篇文章中,簡單分享一下封裝HttpClient工具類的思路及部分代碼,本文將分享如何實現插件式配置HttpClient對象。
? ? ?如果你看過我前面的幾篇關于HttpClient的文章或者官網示例,應該都知道HttpClient對象在創建時,都可以設置各種參數,但是卻沒有簡單的進行封裝,比如對我來說比較重要的3個:代理、ssl(包含繞過證書驗證和自定義證書驗證)、超時。還需要自己寫。所以這里我就簡單封裝了一下,順便還封裝了一個連接池的配置。
? ? ?其實說是插件式配置,那是高大上的說法,說白了,就是采用了建造者模式來創建HttpClient對象(級聯調用)。HttpClient的jar包中提供了一個創建HttpClient對象的類HttpClientBuilder。所以我是創建該類的子類HCB,然后做了一些改動。每個配置方法的返回值都是HCB,這樣就支持級聯調用了。具體代碼如下:
~~~
package com.tgb.ccl.http.httpclient.builder;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import com.tgb.ccl.http.common.SSLs;
import com.tgb.ccl.http.exception.HttpProcessException;
/**
* httpclient創建者
*
* @author arron
* @date 2015年11月9日 下午5:45:47
* @version 1.0
*/
public class HCB extends HttpClientBuilder{
private boolean isSetPool=false;//記錄是否設置了連接池
private boolean isNewSSL=false;//記錄是否設置了更新了ssl
//用于配置ssl
private SSLs ssls = SSLs.getInstance();
private HCB(){}
public static HCB custom(){
return new HCB();
}
/**
* 設置超時時間
*
* @param timeout 超市時間,單位-毫秒
* @return
*/
public HCB timeout(int timeout){
// 配置請求的超時設置
RequestConfig config = RequestConfig.custom()
.setConnectionRequestTimeout(timeout)
.setConnectTimeout(timeout)
.setSocketTimeout(timeout)
.build();
return (HCB) this.setDefaultRequestConfig(config);
}
/**
* 設置ssl安全鏈接
*
* @return
* @throws HttpProcessException
*/
public HCB ssl() throws HttpProcessException {
if(isSetPool){//如果已經設置過線程池,那肯定也就是https鏈接了
if(isNewSSL){
throw new HttpProcessException("請先設置ssl,后設置pool");
}
return this;
}
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", ssls.getSSLCONNSF()).build();
//設置連接池大小
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
return (HCB) this.setConnectionManager(connManager);
}
/**
* 設置自定義sslcontext
*
* @param keyStorePath 密鑰庫路徑
* @return
* @throws HttpProcessException
*/
public HCB ssl(String keyStorePath) throws HttpProcessException{
return ssl(keyStorePath,"nopassword");
}
/**
* 設置自定義sslcontext
*
* @param keyStorePath 密鑰庫路徑
* @param keyStorepass 密鑰庫密碼
* @return
* @throws HttpProcessException
*/
public HCB ssl(String keyStorePath, String keyStorepass) throws HttpProcessException{
this.ssls = SSLs.custom().customSSL(keyStorePath, keyStorepass);
this.isNewSSL=true;
return ssl();
}
/**
* 設置連接池(默認開啟https)
*
* @param maxTotal 最大連接數
* @param defaultMaxPerRoute 每個路由默認連接數
* @return
* @throws HttpProcessException
*/
public HCB pool(int maxTotal, int defaultMaxPerRoute) throws HttpProcessException{
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", ssls.getSSLCONNSF()).build();
//設置連接池大小
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connManager.setMaxTotal(maxTotal);
connManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
isSetPool=true;
return (HCB) this.setConnectionManager(connManager);
}
/**
* 設置代理
*
* @param hostOrIP 代理host或者ip
* @param port 代理端口
* @return
*/
public HCB proxy(String hostOrIP, int port){
// 依次是代理地址,代理端口號,協議類型
HttpHost proxy = new HttpHost(hostOrIP, port, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
return (HCB) this.setRoutePlanner(routePlanner);
}
}
~~~
? ? ?大家可以看到,這個有成員變量,而且不是static類型,所以是非線程安全的。所以我為了方便使用,就效仿HttpClients(其custom方法可以創建HttpClientBuilder實例)寫了一個靜態的custom方法,來返回一個新的HCB實例。將構造方法設置成了private,無法通過new的方式創建實例,所以只能通過custom方法來創建。在想生成HttpClient對象的時候,調用一下build方法就可以了。于是乎就出現了這樣簡單、方便又明了的調用方式:
~~~
HttpClient client = HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl("D:\\keys\\wsriakey","tomcat").build();
~~~
? ? ?說到ssl,還需要另外一個封裝的類,為了其他工具類有可能也會用到ssl,所以就單出來了。不多解釋,直接上代碼:
~~~
/**
* 設置ssl
*
* @author arron
* @date 2015年11月3日 下午3:11:54
* @version 1.0
*/
public class SSLs {
private static final SSLHandler simpleVerifier = new SSLHandler();
private static SSLConnectionSocketFactory sslConnFactory ;
private static SSLs sslutil = new SSLs();
private SSLContext sc;
public static SSLs getInstance(){
return sslutil;
}
public static SSLs custom(){
return new SSLs();
}
// 重寫X509TrustManager類的三個方法,信任服務器證書
private static class SSLHandler implements X509TrustManager, HostnameVerifier{
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws java.security.cert.CertificateException {
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws java.security.cert.CertificateException {
}
@Override
public boolean verify(String paramString, SSLSession paramSSLSession) {
return true;
}
};
// 信任主機
public static HostnameVerifier getVerifier() {
return simpleVerifier;
}
public synchronized SSLConnectionSocketFactory getSSLCONNSF() throws HttpProcessException {
if (sslConnFactory != null)
return sslConnFactory;
try {
SSLContext sc = getSSLContext();
sc.init(null, new TrustManager[] { simpleVerifier }, null);
sslConnFactory = new SSLConnectionSocketFactory(sc, simpleVerifier);
} catch (KeyManagementException e) {
throw new HttpProcessException(e);
}
return sslConnFactory;
}
public SSLs customSSL(String keyStorePath, String keyStorepass) throws HttpProcessException{
FileInputStream instream =null;
KeyStore trustStore = null;
try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
instream = new FileInputStream(new File(keyStorePath));
trustStore.load(instream, keyStorepass.toCharArray());
// 相信自己的CA和所有自簽名的證書
sc= SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build();
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | KeyManagementException e) {
throw new HttpProcessException(e);
}finally{
try {
instream.close();
} catch (IOException e) {}
}
return this;
}
public SSLContext getSSLContext() throws HttpProcessException{
try {
if(sc==null){
sc = SSLContext.getInstance("SSLv3");
}
return sc;
} catch (NoSuchAlgorithmException e) {
throw new HttpProcessException(e);
}
}
}
~~~
? ? ?基本上就是這樣了。在上一篇中遺留了一個小問題,正好在這里說一下。上一篇文中說道提供一個默認的HttpClient實現,其實是2個,分別針對于http和https。方便調用。具體代碼如下:
~~~
//默認采用的http協議的HttpClient對象
private static HttpClient client4HTTP;
//默認采用的https協議的HttpClient對象
private static HttpClient client4HTTPS;
static{
try {
client4HTTP = HCB.custom().build();
client4HTTPS = HCB.custom().ssl().build();
} catch (HttpProcessException e) {
logger.error("創建https協議的HttpClient對象出錯:{}", e);
}
}
/**
* 判斷url是http還是https,直接返回相應的默認client對象
*
* @return 返回對應默認的client對象
* @throws HttpProcessException
*/
private static HttpClient create(String url) throws HttpProcessException {
if(url.toLowerCase().startsWith("https://")){
return client4HTTPS;
}else{
return client4HTTP;
}
}
~~~
? ? ?這樣在使用工具類的時候,如果不需要自定義HttpClient時,就直接用下面的方式調用:
~~~
public static void testSimple() throws HttpProcessException{
String url = "http://tool.oschina.net/";
//簡單調用
String resp = HttpClientUtil.send(url);
System.out.println("請求結果內容長度:"+ resp);
}
~~~
? ? ?好了,插件化配置HttpClient,就是這些內容,在下一篇文章中分享如何插件式配置Header。沒錯,思路還是跟本文一樣。敬請期待吧。
? ? ?代碼已上傳至:[https://github.com/Arronlong/httpclientUtil](https://github.com/Arronlong/httpclientUtil)。
- 前言
- HttpClient3.x之Get請求和Post請求示例
- httpclient3.x中使用HTTPS的方法
- 簡單的利用UrlConnection,后臺模擬http請求
- 輕松把玩HttpClient之模擬post請求示例
- 輕松把玩HttpClient之配置ssl,采用繞過證書驗證實現https
- 輕松把玩HttpClient之配置ssl,采用設置信任自簽名證書實現https
- 輕松把玩HttpClient之設置代理,可以訪問FaceBook
- 輕松把玩HttpClient之封裝HttpClient工具類(一)(現有網上分享中的最強大的工具類)
- 輕松把玩HttpClient之封裝HttpClient工具類(二),插件式配置HttpClient對象
- 輕松把玩HttpClient之封裝HttpClient工具類(三),插件式配置Header
- 輕松把玩HttpClient之封裝HttpClient工具類(四),單線程調用及多線程批量調用測試
- 輕松把玩HttpAsyncClient之模擬post請求示例
- 輕松把玩HttpClient之封裝HttpClient工具類(五),攜帶Cookie的請求
- 輕松把玩HttpClient之封裝HttpClient工具類(六),封裝輸入參數,簡化工具類