package com...util;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
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.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.HttpConnectionFactory;
import org.apache.http.conn.ManagedHttpClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.DefaultHttpResponseParserFactory;
import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SystemDefaultDnsResolver;
import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
/**
* Description HTTP/HTTPS請求(GET/POST)工具
*
*/
public class HttpClientHelper {
private static Logger log = LoggerFactory.getLogger(HttpClientHelper.class);
private static PoolingHttpClientConnectionManager poolConnManager = null;
private static CloseableHttpClient httpClient =null;
public static synchronized CloseableHttpClient getHttpClient(){
if(null==httpClient){
//注冊訪問協議相關的Socket工廠
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http",PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSystemSocketFactory()).build();
//HttpConnection工廠:皮遏制寫請求/解析響應處理器
HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connectionFactory=new
ManagedHttpClientConnectionFactory(DefaultHttpRequestWriterFactory.INSTANCE,
DefaultHttpResponseParserFactory.INSTANCE);
//DNS解析器
DnsResolver dnsResolver=SystemDefaultDnsResolver.INSTANCE;
//創建池化連接管理器
poolConnManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry,connectionFactory,dnsResolver);
//默認為Socket配置
SocketConfig defaultSocketConfig=SocketConfig.custom().setTcpNoDelay(true).build();
poolConnManager.setDefaultSocketConfig(defaultSocketConfig);
// 設置整個連接池的最大連接數
poolConnManager.setMaxTotal(1000);
// 每個路由的默認最大連接,每個路由實際最大連接默認為DefaultMaxPerRoute控制,maxTotal是整個池子最大數
// DefaultMaxPerRoute設置過小無法支持大並發(ConnectPoolTimeoutException: Timeout waiting for connect from pool) 路由是maxTotal的細分
//每個路由最大連接數
poolConnManager.setDefaultMaxPerRoute(1000);
//在從連接池獲取連接時,連接不活躍多長時間后需要一次驗證,默認2S
poolConnManager.setValidateAfterInactivity(5*1000);
//默認請求配置
RequestConfig requestConfig = RequestConfig.custom()
//設置連接超時時間
.setConnectTimeout(2*1000)
//設置等待數據超時時間
.setSocketTimeout(5*1000)
//設置從連接池獲取連接的等待超時時間
.setConnectionRequestTimeout(2000)
.build();
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setConnectionManager(poolConnManager)
//設置連接池不是共享模式
.setConnectionManagerShared(false)
//定期回調空閑連接
.evictIdleConnections(60, TimeUnit.SECONDS)
//定期回收過期
.evictExpiredConnections()
//連接存活時間,如果不設置,根據長連接信息決定
.setConnectionTimeToLive(60, TimeUnit.SECONDS)
//設置默認請求配置
.setDefaultRequestConfig(requestConfig)
// 連接重試策略,是否能keepalive
.setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)
//長連接配置,即獲取長連接生產多少時間
.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
//設置重試次數,默認是3次;當前是禁用
.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
httpClient = httpClientBuilder.build();
//JVM停止或重啟時,關閉連接池釋放連接
Runtime.getRuntime().addShutdownHook(new Thread(){
public void run(){
try{
httpClient.close();
}catch(IOException e){
log.info(e.getMessage());
}
}
});
}
return httpClient;
}
/**
* 發送 GET 請求
*
* @param url
* 接口URL
* @param params
* 接口參數
* @param HeaderJson
* 接口Header參數
* @return
*/
public static String doGet(String url, Map<String, Object> params, JSONObject HeaderJson) {
long a=System.currentTimeMillis();
String apiUrl = url;
StringBuffer param = new StringBuffer();
int i = 0;
for (String key : params.keySet()) {
if (i == 0) {
param.append("?");
} else {
param.append("&");
}
param.append(key).append("=").append(params.get(key));
i++;
}
apiUrl += param;
String result = null;
CloseableHttpClient httpClient = getHttpClient();
httpClient = (CloseableHttpClient) getHttpClients(apiUrl.startsWith("https://")); // https 驗證 http地址可去掉
CloseableHttpResponse response = null;
HttpGet httpGet = null;
try {
httpGet = new HttpGet(apiUrl);
//Header信息,可去掉
System.out.println("HeaderJson--->:"+HeaderJson);
httpGet.addHeader("id", HeaderJson.getString("id"));
httpGet.addHeader("name", HeaderJson.getString("name"));
httpGet.addHeader("sign", HeaderJson.getString("sign") );
httpGet.setHeader("Content-Type", "application/json");
response = httpClient.execute(httpGet);
int status = response.getStatusLine().getStatusCode();
if (status ==HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(response.getEntity(), "UTF-8");
}
}else{
//不推薦使用CloseableHttpResponse.close關閉連接,他將直接關閉Socket,導致長連接不能復用
EntityUtils.consume(response.getEntity());
}
StringBuilder logsb=new StringBuilder();
logsb.append("\n########################################################################\n");
logsb.append("# 發送報文:"+getPlanText(params)+"\n");
logsb.append("# 響應代碼:"+status+"\n");
logsb.append("# 響應報文:"+result+"\n");
logsb.append("# 耗時:"+(System.currentTimeMillis()-a)+"\n");
logsb.append("########################################################################\n");
log.info(logsb.toString());
return result;
} catch (IOException e) {
try {
if(null !=response )
EntityUtils.consume(response.getEntity());
} catch (IOException e1) {
log.error(e.getMessage(), e1);
}
log.error(e.getMessage(), e);
}
return result;
}
/**
* 發送 POST 請求
* @param url
* 接口URL
* @param params
* 參數map
* @return
*/
public static String doPost(String url, Map<String, Object> params) {
long a=System.currentTimeMillis();
String result = null;
HttpPost httpPost = new HttpPost(url);
CloseableHttpClient httpClient = getHttpClient();
httpClient = (CloseableHttpClient) getHttpClients(url.startsWith("https://")); // https 驗證 http地址可去掉
CloseableHttpResponse response = null;
try {
List<NameValuePair> pairList = new ArrayList<>(params.size());
for (Map.Entry<String, Object> entry : params.entrySet()) {
NameValuePair pair = new BasicNameValuePair(entry.getKey(),entry.getValue().toString());
pairList.add(pair);
}
httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));
response = httpClient.execute(httpPost);
int status = response.getStatusLine().getStatusCode();
if (status ==HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(response.getEntity(), "UTF-8");
}
}else{
//不推薦使用CloseableHttpResponse.close關閉連接,他將直接關閉Socket,導致長連接不能復用
EntityUtils.consume(response.getEntity());
}
StringBuilder logsb=new StringBuilder();
logsb.append("\n########################################################################\n");
logsb.append("# 發送報文:"+getPlanText(params)+"\n");
logsb.append("# 響應代碼:"+status+"\n");
logsb.append("# 響應報文:"+result+"\n");
logsb.append("# 耗時:"+(System.currentTimeMillis()-a)+"\n");
logsb.append("########################################################################\n");
log.info(logsb.toString());
return result;
} catch (Exception e) {
try {
if(null !=response )
EntityUtils.consume(response.getEntity());
} catch (IOException e1) {
log.error(e.getMessage(), e1);
}
log.error(e.getMessage(), e);
}
return result;
}
/**
* 參數Map格式化
* @param map
* @return
*/
public static String getPlanText(Map<String, Object> map) {
StringBuilder sb=new StringBuilder();
for(Map.Entry<String, Object> entry :map.entrySet()){
sb.append(entry.getKey()).
append("=").
append(entry.getValue())
.append("&");
}
if(sb.length()>0){
sb.deleteCharAt(sb.length()-1);
}
return sb.toString();
}
private static HttpClient getHttpClients(boolean isHttps) {
if (isHttps) {
SSLContext sslContext = createIgnoreVerifySSL();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https",
new SSLConnectionSocketFactory(sslContext)).build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
socketFactoryRegistry);
return HttpClients.custom().setConnectionManager(connManager)
.build();
} else {
return HttpClients.createDefault();
}
}
private static SSLContext createIgnoreVerifySSL() {
try {
SSLContext sc = SSLContext.getInstance("SSL");
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
X509Certificate[] x509Certificates, String paramString) {
}
@Override
public void checkServerTrusted(
X509Certificate[] x509Certificates, String paramString) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[] { trustManager }, null);
return sc;
} catch (KeyManagementException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}