package com.XXXXXX.XXXXXXX.utils; import java.io.InputStream; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.ProtocolException; import org.apache.http.client.RedirectStrategy; import org.apache.http.client.config.CookieSpecs; 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.methods.HttpUriRequest; 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.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; 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.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * http 鏈接工具類 * @ClassName: HttpClientUtil * @date 2017年9月16日 上午11:46:45 */ public class HttpClientUtil { private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class); private static PoolingHttpClientConnectionManager connectionManager; private static final Timer connectionManagerTimer = new Timer("SimpleRouteFilter.connectionManagerTimer", true); static{ connectionManager = newConnectionManager(); connectionManagerTimer.schedule(new TimerTask() { public void run() { if (connectionManager == null) { return; } connectionManager.closeExpiredConnections(); //釋放掉過時的連接 } }, 30000, 5000); } /** * 建立鏈接池 * @CreateTime: 2017年9月16日 下午12:01:54 * @UpdateTime: 2017年9月16日 下午12:01:54 * @return */ private static PoolingHttpClientConnectionManager newConnectionManager(){ try{ final SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, new TrustManager[] { new X509TrustManager() { public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } } }, new SecureRandom()); RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder .<ConnectionSocketFactory> create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslContext)); final Registry<ConnectionSocketFactory> registry = registryBuilder.build(); connectionManager = new PoolingHttpClientConnectionManager(registry); /** * maxTotal 與 MaxPerRoute 解釋: * 路由的默認最大鏈接(該值默認爲2)限制數量實際使用DefaultMaxPerRoute並不是MaxTotal * 設置太小沒法支持大併發(ConnectionPoolTimeoutException: Timeout waiting for connection from pool) * 路由是對maxTotal的細分例如:MaxtTotal=400 DefaultMaxPerRoute=200 * 而我只鏈接到http://sishuok.com時,到這個主機的併發最多隻有200;而不是400; * 而我鏈接到http://sishuok.com 和 http://qq.com時,到每一個主機的併發最多隻有200;即加起來是400(但不能超過400) */ connectionManager.setMaxTotal(400);//設置整個鏈接池最大鏈接數 connectionManager.setDefaultMaxPerRoute(200);//每一個主機的併發最多隻有200 //this.connectionManager.setValidateAfterInactivity(ms); return connectionManager; }catch (Exception e) { throw new RuntimeException(e); } } /** * 建立鏈接 * @CreateTime: 2017年9月16日 下午12:02:14 * @UpdateTime: 2017年9月16日 下午12:02:14 * @param timeOut * @return */ private static CloseableHttpClient getHttpClient(int timeOut){ final RequestConfig requestConfig = RequestConfig.custom() //.setSocketTimeout(PropertyPlaceholder.getInt("proxyClient.socket_timeout"))//請求獲取數據的超時時間 .setSocketTimeout(timeOut)//請求獲取數據的超時時間 .setConnectTimeout(200000)//設置鏈接超時時間,單位毫秒。 .setConnectionRequestTimeout(3000000)//設置從鏈接池獲取鏈接超時時間、若是不設置,默認爲connection_timeout所以必定要設置並且不能太大 .setCookieSpec(CookieSpecs.IGNORE_COOKIES).build(); HttpClientBuilder httpClientBuilder = HttpClients.custom(); return httpClientBuilder.setConnectionManager(connectionManager) .setDefaultRequestConfig(requestConfig) .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))//不進行重試 .setRedirectStrategy(new RedirectStrategy() { //重定向問題 public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { return false; } public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { return null; } }).build(); } public static String httpRequest(String requestUrl,Map<String, String> params, String requestbody) { String result = ""; CloseableHttpClient httpclient = null; try { httpclient = getHttpClient(100000000);//默認超時時間爲30s if(null != params && params.size() > 0){ requestUrl = requestUrl + "?"; for(String key : params.keySet()){ requestUrl = requestUrl + key + "=" + params.get(key) + "&"; } } logger.info("httpCinet 發送請求地址:{}",requestUrl); HttpPost httpPost = new HttpPost(requestUrl); //設置請求的body if(StringUtils.isNotBlank(requestbody)){ httpPost.setEntity(new StringEntity(requestbody, "UTF-8")); } long startTime = System.currentTimeMillis(); CloseableHttpResponse response = httpclient.execute(httpPost); //httpPost.releaseConnection(); logger.info("httpCinet 發送請求地址:{},共花費了:{} ms",requestUrl,(System.currentTimeMillis()-startTime)); try { InputStream in=response.getEntity().getContent(); result = IOUtils.toString(in); //httpPost.releaseConnection(); in.close();//bufferedReader.close();做用就是將用完的鏈接釋放,下次請求能夠複用 } finally { //這裏特別注意的是,若是不使用in.close();而僅僅使用response.close();結果就是鏈接會被關閉,而且不能被複用,這樣就失去了採用鏈接池的意義 response.close(); } } catch (Exception e) { logger.error(e.getMessage(),e); } return result; } }