HttpClient工具類


依賴pom

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>

工具類

package com.hjf.boot.demo.boot_start;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpClientUtil {
private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
private final static int CONNECT_TIMEOUT = 4000;// 連接超時毫秒
private final static int SOCKET_TIMEOUT = 10000;// 傳輸超時毫秒
private final static int REQUESTCONNECT_TIMEOUT = 3000;// 獲取請求超時毫秒
private final static int CONNECT_TOTAL = 200;// 最大連接數
private final static int CONNECT_ROUTE = 20;// 每個路由基礎的連接數
private final static String ENCODE_CHARSET = "utf-8";// 響應報文解碼字符集
private final static String RESP_CONTENT = "通信失敗";
private static PoolingHttpClientConnectionManager connManager = null;
private static CloseableHttpClient httpClient = null;
static {
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
LayeredConnectionSocketFactory sslsf = createSSLConnSocketFactory();
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", plainsf).register("https", sslsf).build();
connManager = new PoolingHttpClientConnectionManager(registry);
// 將最大連接數增加到200
connManager.setMaxTotal(CONNECT_TOTAL );
// 將每個路由基礎的連接增加到20
connManager.setDefaultMaxPerRoute(CONNECT_ROUTE );
// 可用空閑連接過期時間,重用空閑連接時會先檢查是否空閑時間超過這個時間,如果超過,釋放socket重新建
立
connManager.setValidateAfterInactivity(30000);
// 設置socket超時時間
SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(SOCKET_TIMEOUT ).build();
connManager.setDefaultSocketConfig(socketConfig);
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(REQUESTCONNECT_T
IMEOUT )
.setConnectTimeout(CONNECT_TIMEOUT ).setSocketTimeout(SOCKET_TIMEOUT ).build();
HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
if (executionCount >= 3) {// 如果已經重試了3次,就放棄
return false;
}
if (exception instanceof NoHttpResponseException) {// 如果服務器丟掉了連接,那么就重試
return true;
}
if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
return false;
}
if (exception instanceof InterruptedIOException) {// 超時
return true;
}
if (exception instanceof UnknownHostException) {// 目標服務器不可達
return false;
}
if (exception instanceof ConnectTimeoutException) {// 連接被拒絕
return false;
}
if (exception instanceof SSLException) {// ssl握手異常
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
// 如果請求是冪等的,就再次嘗試
if (!(request instanceof HttpEntityEnclosingRequest)) {
return true;
}
return false;
}
};
httpClient = HttpClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(request
Config)
.setRetryHandler(httpRequestRetryHandler).build();
if (connManager != null && connManager.getTotalStats() != null) {
logger.info("now client pool " + connManager.getTotalStats().toString());
}
}
/**
* 發送HTTP_GET請求
*
* @see 1)該方法會自動關閉連接,釋放資源
* @see 2)方法內設置了連接和讀取超時時間,單位為毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
* @see 3)請求參數含中文時,經測試可直接傳入中文,HttpClient會自動編碼發給Server,應用時應根據實際效果決
定傳入前是否轉碼
* @see 4)該方法會自動獲取到響應消息頭中[Content-Type:text/html; charset=GBK]的charset值作為響應報文的
解碼字符集
* @see 若響應消息頭中無Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1作為響應報文的解碼字符
集
* @param requestURL 請求地址(含參數)
* @return 遠程主機響應正文
*/
public static String sendGetRequest(String reqURL, String param) {
if (null != param) {
reqURL += "?" + param;
}
String respContent = RESP_CONTENT ; // 響應內容
// reqURL = URLDecoder.decode(reqURL, ENCODE_CHARSET);
HttpGet httpget = new HttpGet(reqURL);
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httpget, HttpClientContext.create()); // 執行GET請求
HttpEntity entity = response.getEntity(); // 獲取響應實體
if (null != entity) {
Charset respCharset = ContentType.getOrDefault(entity).getCharset();
respContent = EntityUtils.toString(entity, respCharset);
EntityUtils.consume(entity);
}
} catch (ConnectTimeoutException cte) {
logger.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
} catch (SocketTimeoutException ste) {
logger.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
} catch (ClientProtocolException cpe) {
// 該異常通常是協議錯誤導致:比如構造HttpGet對象時傳入協議不對(將'http'寫成'htp')or響應內容不符合
HTTP協議要求等
logger.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
} catch (ParseException pe) {
logger.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
} catch (IOException ioe) {
// 該異常通常是網絡原因引起的,如HTTP服務器未啟動等
logger.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
} catch (Exception e) {
logger.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
} finally {
try {
if (response != null)
response.close();
} catch (IOException e) {
e.printStackTrace();
}
if (httpget != null) {
httpget.releaseConnection();
}
}
return respContent;
}
public static String sendPostRequest(String reqURL, String param) {
return sendPostRequest(reqURL, param, "");
}
/**
* 發送HTTP_POST請求 type: 默認是表單請求,
* @see 1)該方法允許自定義任何格式和內容的HTTP請求報文體
* @see 2)該方法會自動關閉連接,釋放資源
* @see 3)方法內設置了連接和讀取超時時間,單位為毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
* @see 4)請求參數含中文等特殊字符時,可直接傳入本方法,並指明其編碼字符集encodeCharset參數,方法內部會自
動對其轉碼
* @see 5)該方法在解碼響應報文時所采用的編碼,取自響應消息頭中的[Content-Type:text/html; charset=GBK]的
charset值
* @see 若響應消息頭中未指定Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1
* @param reqURL 請求地址
* @param reqData 請求參數,若有多個參數則應拼接為param11=value11&22=value22&33=value33的形式
* @param encodeCharset 編碼字符集,編碼請求數據時用之,此參數為必填項(不能為""或null)
* @return 遠程主機響應正文
*/
public static String sendPostRequest(String reqURL, String param, String type) {
String result = RESP_CONTENT ;
// 設置請求和傳輸超時時間
HttpPost httpPost = new HttpPost(reqURL);
// 這就有可能會導致服務端接收不到POST過去的參數,比如運行在Tomcat6.0.36中的Servlet,所以我們手工指定C
ONTENT_TYPE頭消息
if (type != null && type.length() > 0) {
httpPost.setHeader(HTTP.CONTENT_TYPE, "application/json; charset=" + ENCODE_CHARSET );
} else {
httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + ENCO
DE_CHARSET );
}
CloseableHttpResponse response = null;
try {
if (param != null) {
StringEntity entity = new StringEntity(param, ENCODE_CHARSET );
httpPost.setEntity(entity);
}
logger.info("開始執行請求:" + reqURL);
// reqURL = URLDecoder.decode(reqURL, ENCODE_CHARSET);
response = httpClient.execute(httpPost, HttpClientContext.create());
HttpEntity entity = response.getEntity();
if (null != entity) {
result = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
logger.info("執行請求完畢:" + result);
EntityUtils.consume(entity);
}
} catch (ConnectTimeoutException cte) {
logger.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
} catch (SocketTimeoutException ste) {
logger.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
} catch (ClientProtocolException cpe) {
logger.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
} catch (ParseException pe) {
logger.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
} catch (IOException ioe) {
logger.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
} catch (Exception e) {
logger.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
} finally {
try {
if (response != null)
response.close();
} catch (IOException e) {
e.printStackTrace();
}
if (httpPost != null) {
httpPost.releaseConnection();
}
}
return result;
}
//SSL的socket工廠創建
private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
SSLConnectionSocketFactory sslsf = null;
// 創建TrustManager() 用於解決javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
X509TrustManager trustManager = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String authType) throws CertificateExce
ption {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String authType) throws CertificateExce
ption {
// TODO Auto-generated method stub
}
};
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
sslContext.init(null, new TrustManager[] {(TrustManager)trustManager}, null);
// 創建SSLSocketFactory , // 不校驗域名 ,取代以前驗證規則
sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sslsf;
}
public static Map<HttpRoute, PoolStats> getConnManagerStats() {
if (connManager != null) {
Set<HttpRoute> routeSet = connManager.getRoutes();
if (routeSet != null && !routeSet.isEmpty()) {
Map<HttpRoute, PoolStats> routeStatsMap = new HashMap<HttpRoute, PoolStats>();
for (HttpRoute route : routeSet) {
PoolStats stats = connManager.getStats(route);
routeStatsMap.put(route, stats);
}
return routeStatsMap;
}
}
return null;
}
public static PoolStats getConnManagerTotalStats() {
if (connManager != null) {
return connManager.getTotalStats();
}
return null;
}
/**
* 關閉系統時關閉httpClient
*/
public static void releaseHttpClient() {
try {
httpClient.close();
} catch (IOException e) {
logger.error("關閉httpClient異常" + e);
} finally {
if (connManager != null) {
connManager.shutdown();
}
}
}
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM