3 import lombok.extern.slf4j.Slf4j;
4 import org.apache.http.HttpEntity;
5 import org.apache.http.HttpResponse;
6 import org.apache.http.HttpStatus;
7 import org.apache.http.NameValuePair;
8 import org.apache.http.client.HttpRequestRetryHandler;
9 import org.apache.http.client.config.RequestConfig;
10 import org.apache.http.client.entity.UrlEncodedFormEntity;
11 import org.apache.http.client.methods.CloseableHttpResponse;
12 import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
13 import org.apache.http.client.methods.HttpPost;
14 import org.apache.http.client.methods.HttpRequestBase;
15 import org.apache.http.config.Registry;
16 import org.apache.http.config.RegistryBuilder;
17 import org.apache.http.conn.socket.ConnectionSocketFactory;
18 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
19 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
20 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
21 import org.apache.http.entity.StringEntity;
22 import org.apache.http.impl.client.CloseableHttpClient;
23 import org.apache.http.impl.client.HttpClients;
24 import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
25 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
26 import org.apache.http.message.BasicNameValuePair;
27 import org.apache.http.ssl.SSLContextBuilder;
28 import org.apache.http.util.EntityUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import java.io.IOException;
33 import java.io.UnsupportedEncodingException;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.concurrent.ScheduledExecutorService;
39 import java.util.concurrent.ScheduledThreadPoolExecutor;
40 import java.util.concurrent.TimeUnit;
41
42 /**
43 * @author suyuj
44 * 可为每个域名设置单独的连接池数量
45 * connectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.baidu.com")), 1);
46 * setConnectTimeout表示设置建立连接的超时时间
47 * setConnectionRequestTimeout表示从连接池中拿连接的等待超时时间
48 * setSocketTimeout表示发出请求后等待对端应答的超时时间
49 */
50
51 @Slf4j
52 public class HttpConnectionPoolUtils {
53
54 private static final Logger LOGGER = LoggerFactory.getLogger(HttpConnectionPoolUtils.class);
55
56 private static final String ENCODING = "UTF-8";
57
58 private static PoolingHttpClientConnectionManager connectionManager = null;
59
60 private static CloseableHttpClient httpClient;
61
62 static {
63 LOGGER.info("初始化http connection 连接池 ...");
64 try {
65 // 配置同时支持 HTTP 和 HTPPS
66 SSLContextBuilder builder = new SSLContextBuilder();
67 builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
68 SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(builder.build());
69 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslConnectionSocketFactory).build();
70 connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
71 }catch (Exception e){
72 LOGGER.error("初始化http 连接池异常",e);
73 connectionManager = new PoolingHttpClientConnectionManager();
74 }
75 // 总连接池数量
76 connectionManager.setMaxTotal(20);
77 connectionManager.setDefaultMaxPerRoute(100);
78 RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(1000).setConnectionRequestTimeout(2000).setSocketTimeout(3000).build();
79 HttpRequestRetryHandler retryHandler = new StandardHttpRequestRetryHandler();
80
81 httpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).setRetryHandler(retryHandler).build();
82
83 ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
84 scheduledExecutorService.scheduleWithFixedDelay(() -> {
85 connectionManager.closeExpiredConnections();
86 connectionManager.closeIdleConnections(20,TimeUnit.SECONDS);
87 LOGGER.info("回收过期的http连接完成 status:{}",connectionManager.getTotalStats());
88 },30,120,TimeUnit.SECONDS);
89
90 Runtime.getRuntime().addShutdownHook(new Thread(() -> {
91 log.info("关闭 httpClient 连接");
92 try {
93 if(httpClient != null){
94 httpClient.close();
95 }
96 } catch (IOException e) {
97 log.error("关闭 httpClient 异常",e);
98 }
99 }));
100 }
101
102 public static HttpClientResult doPost(String url, Map<String, String> params) throws IOException {
103 return doPost(url, null, params);
104 }
105
106 public static HttpClientResult doPost(String url, Map<String, String> headers, Map<String, String> params) throws IOException {
107
108 log.info("http post 请求:url={}", url);
109 log.info("http post 请求:params = {}", params);
110 // 创建httpClient对象
111 HttpPost httpPost = new HttpPost(url);
112 packageHeader(headers, httpPost);
113 // 封装请求参数
114 try {
115 packageParam(params, httpPost);
116 } catch (UnsupportedEncodingException e) {
117 throw e;
118 }
119
120 // 创建httpResponse对象
121 CloseableHttpResponse httpResponse = null;
122
123 try {
124 // 执行请求并获得响应结果
125 long startTime = System.currentTimeMillis();
126 HttpClientResult httpClientResult = getHttpClientResult(httpResponse, httpClient, httpPost);
127 long endTime = System.currentTimeMillis();
128 log.info("http post 请求相应时间:{}", (endTime-startTime));
129 log.info("http post 请求返回结果:{}", httpClientResult);
130 return httpClientResult;
131 } catch (Exception e) {
132 throw e;
133 } finally {
134 // 释放资源
135 if (httpResponse != null) {
136 httpResponse.close();
137 }
138 }
139 }
140
141 public static void packageHeader(Map<String, String> params, HttpRequestBase httpMethod) {
142 // 封装请求头
143 if (params != null) {
144 Set<Map.Entry<String, String>> entrySet = params.entrySet();
145 for (Map.Entry<String, String> entry : entrySet) {
146 // 设置到请求头到HttpRequestBase对象中
147 httpMethod.setHeader(entry.getKey(), entry.getValue());
148 }
149 }
150 }
151
152 public static void packageParam(Map<String, String> params, HttpEntityEnclosingRequestBase httpMethod)
153 throws UnsupportedEncodingException {
154 // 封装请求参数
155 if (params != null) {
156 List<NameValuePair> nvps = new ArrayList<NameValuePair>();
157 Set<Map.Entry<String, String>> entrySet = params.entrySet();
158 for (Map.Entry<String, String> entry : entrySet) {
159 nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
160 }
161
162 // 设置到请求的http对象中
163 httpMethod.setEntity(new UrlEncodedFormEntity(nvps, ENCODING));
164 }
165 }
166
167 public static HttpClientResult getHttpClientResult(CloseableHttpResponse httpResponse,
168 CloseableHttpClient httpClient, HttpRequestBase httpMethod) throws IOException {
169 // 执行请求
170 httpResponse = httpClient.execute(httpMethod);
171
172 // 获取返回结果
173 if (httpResponse != null && httpResponse.getStatusLine() != null) {
174 String content = "";
175 if (httpResponse.getEntity() != null) {
176 content = EntityUtils.toString(httpResponse.getEntity(), ENCODING);
177 }
178 return new HttpClientResult(httpResponse.getStatusLine().getStatusCode(), content);
179 }
180 return new HttpClientResult(HttpStatus.SC_INTERNAL_SERVER_ERROR);
181 }
182
183 public static String doPost(String url,String postBody) throws IOException {
184 HttpPost httpPost = new HttpPost(url);
185 StringEntity entity = new StringEntity(postBody,"utf-8");
186 entity.setContentEncoding("UTF-8");
187 entity.setContentType("application/json");
188 httpPost.setEntity(entity);
189 HttpResponse resp = httpClient.execute(httpPost);
190
191 String respContent = "";
192 if(resp.getStatusLine().getStatusCode() == 200) {
193 HttpEntity he = resp.getEntity();
194 respContent = EntityUtils.toString(he,"UTF-8");
195 }
196 return respContent;
197 }
198 }
199