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; } }