HTTPClient 提供了一个高效、最新且功能丰富的包,实现了最新 HTTP 标准和建议的客户端。

添加依赖

1
2
3
4
5
6
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>

连接池

降低频繁建立和断开 HTTP 连接对资源的消耗,就需要使用 HTTP 连接池来管理连接,并保证一定数量的长连接,使系统能拥有更高的并发性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private static volatile PoolingHttpClientConnectionManager cm;

public static PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() throws Exception {
if (cm == null) {
synchronized(HttpUtils.class) {
if (cm == null) {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
// 信任所有
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();

// ALLOW_ALL_HOSTNAME_VERIFIER:这个主机名验证器基本上是关闭主机名验证的,实现的是一个空操作,并且不会抛出javax.net.ssl.SSLException异常。
X509HostnameVerifier allowAllHostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext, new String[] {
"TLSv1.2"
}, null, allowAllHostnameVerifier);

Registry < ConnectionSocketFactory > registry = RegistryBuilder. < ConnectionSocketFactory > create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslsf)
.build();

cm = new PoolingHttpClientConnectionManager(registry);
//最大连接数
cm.setMaxTotal(300);
//每个路由最大连接数,路由指IP+PORT或者域名
cm.setDefaultMaxPerRoute(20);
}
}
}

return cm;
}

超时时间

根据上游系统的响应时间,设置合理的超时时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static CloseableHttpClient buildSSLCloseableHttpClient() throws Exception {

// 创建请求配置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(2000) // 连接超时时间
.setConnectionRequestTimeout(3000) // 请求超时时间
.setSocketTimeout(5000) // 套接字超时时间
.build();

return HttpClients
.custom()
.setConnectionManager(getPoolingHttpClientConnectionManager())
.setDefaultRequestConfig(requestConfig)
// 禁止重试
.disableAutomaticRetries()
.build();
}

释放资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static String doPost(String url, com.alibaba.fastjson.JSONObject param, String authorization) {
HttpResponse response = null;
HttpPost httpPost = new HttpPost(url);
CloseableHttpClient httpClient = null;
try {
httpPost.addHeader("Content-Type", "application/json;charset=utf-8");

StringEntity entity = new StringEntity(param.toString(), "utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);

httpClient = buildSSLCloseableHttpClient();
response = httpClient.execute(httpPost);
String resultStr = EntityUtils.toString(response.getEntity(), "utf-8");
log.info("请求地址:" + url + ",请求参数:" + param.toString() + ",返回值:" + resultStr);
return resultStr;
} catch (Exception e) {
log.error(String.format("doPost URL=%s PARAM=%s ERROR:", url, param.toJSONString()), e);
throw new RuntimeException(String.format("doPost URL=%s PARAM=%s ERROR %s", url, param.toJSONString(), e.getMessage()));
} finally {
// 释放资源
if (response != null) {
try {
EntityUtils.consume(response.getEntity());
} catch (IOException e) {
log.error("doPost EntityUtils.consume error:", e);
}
}
}
}