http與https建立CloseableHttpClient
阿新 • • 發佈:2018-12-04
import java.io.IOException; import java.io.InterruptedIOException; import java.net.URL; import java.net.UnknownHostException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Map; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpStatus; import org.apache.http.NoHttpResponseException; 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.HttpPost; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; 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.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; 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.protocol.HttpContext; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.nucc.NuccConstants; import com.nucc.base.BankTxnException; public class HttpClientUtil { private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class); private static CloseableHttpClient poolHttpClient = null; private final static Object syncLock = new Object(); public static final String DEFAULT_SEND_CHARSET = "UTF-8"; public static final String DEFAULT_RES_CHARSET = "UTF-8"; private static final RequestConfig config; static { config = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(60000).build(); } /** * * <p>Title: doPostPooling</p> * <p>Description: </p> * @param url * @param headers * @param dataContent * @return * @throws Exception */ public static String doPostPooling(String url, Map<String, String> headers, String dataContent) throws Exception { return doPostPooling(url, headers, dataContent, "application/xml", DEFAULT_SEND_CHARSET, DEFAULT_RES_CHARSET); } /** * * <p>Title: doPostPooling</p> * <p>Description: </p> * @param url * @param headers * @param dataContent * @param contentType * @param reqCharset * @param resCharset * @return * @throws Exception */ private static String doPostPooling(String url, Map<String, String> headers, String dataContent, String contentType, String reqCharset, String resCharset) throws Exception { CloseableHttpResponse response = null; if (StringUtils.isBlank(url)) { return null; } CloseableHttpClient httpClient = getPoolingHttpClient(config, url); HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Content-Type", contentType); for (Map.Entry<String, String> entry : headers.entrySet()) { httpPost.addHeader(entry.getKey(), entry.getValue()); } HttpEntity reqentity = new StringEntity(dataContent, ContentType.create(contentType, reqCharset)); httpPost.setEntity(reqentity); response = httpClient.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { logger.error("HttpClientEpcc.doPostPooling : 狀態碼非200, 為 " + statusCode); httpPost.abort(); throw new BankTxnException(NuccConstants.httpRspError, "狀態碼非200, 為 :" + statusCode); } HttpEntity entity = response.getEntity(); String result = null; if (entity != null) { result = EntityUtils.toString(entity, resCharset == null ? DEFAULT_RES_CHARSET : resCharset); } EntityUtils.consume(entity); response.close(); if (response != null) response.close(); return result; } /** * * <p>Title: getPoolingHttpClient</p> * <p>Description: </p> * @param config * @param url * @return * @throws Exception */ private static CloseableHttpClient getPoolingHttpClient(RequestConfig config, String url) throws Exception { URL u = new URL(url); String hostname = u.getHost(); int port = u.getPort(); if (port == -1) { port = "https".equals(u.getProtocol()) ? 443 : 80; } if (poolHttpClient == null) { synchronized (syncLock) { if (poolHttpClient == null) { poolHttpClient = createPoolingConnection(config, 400, 40, 100, hostname, port); } } } return poolHttpClient; } /** * * <p>Title: createPoolingConnection</p> * <p>Description: </p> * @param config * @param maxTotal * @param maxPerRoute * @param maxRoute * @param hostname * @param port * @return * @throws Exception */ private static CloseableHttpClient createPoolingConnection(RequestConfig config, int maxTotal, int maxPerRoute, int maxRoute, String hostname, int port) throws Exception { CloseableHttpClient httpClient = null; ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory(); SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { return true; } }).build(); // X509TrustManager trustManager = new X509TrustManager() { // @Override // public X509Certificate[] getAcceptedIssuers() { // return null; // } // @Override // public void checkClientTrusted(X509Certificate[] xcs, String str) {} // @Override // public void checkServerTrusted(X509Certificate[] xcs, String str) {} // }; SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); // SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS); // ctx.init(null, new TrustManager[] { trustManager }, null); // SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE); // SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, // new String[] { "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_256_GCM_SHA384" }, // SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", plainsf).register("https", sslsf).build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry); // 將最大連線數增加 cm.setMaxTotal(maxTotal); // 將每個路由基礎的連線增加 cm.setDefaultMaxPerRoute(maxPerRoute); HttpHost httpHost = new HttpHost(hostname, port); // 將目標主機的最大連線數增加 cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute); // 請求重試處理 HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { @Override public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount >= 5) {// 如果已經重試了5次,就放棄 return false; } if (exception instanceof NoHttpResponseException) {// 如果伺服器丟掉了連線,那麼就重試 return true; } if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常 return false; } if (exception instanceof InterruptedIOException) {// 超時 return false; } 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(cm).setDefaultRequestConfig(config) .setRetryHandler(httpRequestRetryHandler).build(); return httpClient; } }