一、HttpClient 4.x 强制启用 TLSv1.2
HttpClient 4.x 默认支持 TLSv1.2(前提是你的 JDK 支持),如需强制指定协议,需自定义 SSLContext。
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(null, new TrustAllStrategy()) // 信任所有证书,仅测试用
.build();
// 只启用 TLSv1.2
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[] { "TLSv1.2" }, // 只允许 TLSv1.2
null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
HttpGet get = new HttpGet("https://your-tls-server.com/");
try (CloseableHttpResponse resp = client.execute(get)) {
System.out.println(EntityUtils.toString(resp.getEntity()));
}
二、HttpClient 5.x 强制启用 TLSv1.3
HttpClient 5.x 支持 TLSv1.3(需 JDK11+),配置方式类似。
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.hc.core5.ssl.TrustAllStrategy;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.classic.CloseableHttpResponse;
import org.apache.hc.core5.http.io.entity.EntityUtils;
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(new TrustAllStrategy()) // 信任所有证书,仅测试用
.build();
// 只启用 TLSv1.3
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[] { "TLSv1.3" }, // 只允许 TLSv1.3
null,
(hostname, session) -> true // 信任所有主机名,仅测试用
);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
HttpGet get = new HttpGet("https://your-tls13-server.com/");
try (CloseableHttpResponse resp = client.execute(get)) {
System.out.println(EntityUtils.toString(resp.getEntity()));
}
三、自动选择协议(推荐)
其实一般情况下,HttpClient 会自动协商支持的最高 TLS 协议版本,只要你的 JDK 支持 TLSv1.2/1.3,无需强制指定:
CloseableHttpClient client = HttpClients.createDefault();
HttpGet get = new HttpGet("https://your-server.com/");
try (CloseableHttpResponse resp = client.execute(get)) {
System.out.println(EntityUtils.toString(resp.getEntity()));
}
四、常见注意事项
- JDK版本要求:TLSv1.3 需 JDK11 及以上,TLSv1.2 需 JDK8 及以上。
- 生产环境不要用 TrustAllStrategy 和 ALLOW_ALL_HOSTNAME_VERIFIER,应配置 CA 证书和主机名校验。
- 服务端必须支持 TLSv1.2/1.3,否则连接会失败。
- 如需同时支持 TLSv1.2 和 TLSv1.3,可在协议数组中同时配置:
new String[]{"TLSv1.2", "TLSv1.3"}。
五、生产环境安全配置(服务端证书校验)
在生产环境下,不要用 TrustAllStrategy 或 ALLOW_ALL_HOSTNAME_VERIFIER,应加载受信任的 CA 证书,并严格校验主机名。
1. 加载自定义 CA 证书
假设你的服务端证书由内部 CA 签发,需要客户端信任:
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import java.io.File;
import java.security.KeyStore;
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream instream = new FileInputStream(new File("ca.jks"))) {
trustStore.load(instream, "your_ca_password".toCharArray());
}
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(trustStore, null)
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[] { "TLSv1.2", "TLSv1.3" }, // 支持协议
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier() // 严格校验主机名
);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
六、双向认证(客户端证书)
部分金融、政务等场景需要客户端也携带证书(双向认证)。
1. 客户端证书为 PKCS12 (.p12/.pfx)
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream keyStream = new FileInputStream("client.p12")) {
keyStore.load(keyStream, "client_cert_password".toCharArray());
}
SSLContext sslContext = SSLContextBuilder.create()
.loadKeyMaterial(keyStore, "client_cert_password".toCharArray()) // 加载客户端证书
.loadTrustMaterial(trustStore, null) // 加载信任 CA
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[] { "TLSv1.2", "TLSv1.3" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier()
);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
七、协议调试与排查
1. 查看实际协商的协议版本
可以通过 Java 的 debug 参数:
-Djavax.net.debug=ssl:handshake
运行后会看到类似:
*** ServerHello, TLSv1.3
表示实际协商的是 TLSv1.3。
2. OpenSSL 命令行测试
测试服务端支持的协议:
openssl s_client -connect your-server.com:443 -tls1_2
openssl s_client -connect your-server.com:443 -tls1_3
如果连接成功,说明服务端支持该协议。
八、常见问题与解决办法
-
报错:
javax.net.ssl.SSLHandshakeException: Received fatal alert: protocol_version- 原因:客户端或服务端协议版本不兼容。检查 JDK 版本、服务端配置。
-
报错:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException- 原因:证书未被信任。需导入服务端 CA 证书到客户端 truststore。
-
TLSv1.3不生效?
- 检查 JDK 版本(需 JDK11+)、服务端配置(如 Nginx/Tomcat/OpenSSL 支持 TLSv1.3)。
-
双向认证失败?
- 检查客户端证书格式、密码是否正确,服务端是否要求客户端证书。
九、完整生产级 HttpClient TLSv1.2/1.3 示例(双向认证)
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("ca.jks"), "ca_password".toCharArray());
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("client.p12"), "client_password".toCharArray());
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(trustStore, null)
.loadKeyMaterial(keyStore, "client_password".toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[] { "TLSv1.2", "TLSv1.3" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier()
);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
HttpGet get = new HttpGet("https://secure-server.com/");
try (CloseableHttpResponse resp = client.execute(get)) {
System.out.println(EntityUtils.toString(resp.getEntity()));
}
十、参考配置(Nginx/Tomcat/OpenSSL)
- Nginx 配置 TLSv1.3:
ssl_protocols TLSv1.2 TLSv1.3; - Tomcat 配置 TLSv1.3:
<Connector ... sslEnabledProtocols="TLSv1.2,TLSv1.3" ... /> - OpenSSL 查看支持协议:
openssl version
十一、连接池管理(高并发场景推荐)
在生产环境,尤其是高并发调用时,推荐使用连接池来管理 HttpClient 的连接,提升性能和资源利用率。
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
// 创建连接池管理器
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
connManager.setMaxTotal(200); // 最大连接数
connManager.setDefaultMaxPerRoute(50); // 每个路由最大连接数
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(connManager)
.build();
配合前文的 SSL/TLS 配置,可以将
.setSSLSocketFactory(sslsf)一起用。
十二、异步请求(HttpAsyncClient,适合批量/实时场景)
Apache HttpAsyncClient 支持异步 HTTP 请求,减少阻塞、提升吞吐量。
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
CloseableHttpAsyncClient asyncClient = HttpAsyncClients.createDefault();
asyncClient.start();
HttpGet get = new HttpGet("https://your-tls-server.com/");
asyncClient.execute(get, new FutureCallback<org.apache.http.HttpResponse>() {
public void completed(org.apache.http.HttpResponse response) {
System.out.println("Response: " + response.getStatusLine());
}
public void failed(Exception ex) {
System.out.println("Failed: " + ex.getMessage());
}
public void cancelled() {
System.out.println("Cancelled");
}
});
十三、证书自动更新(信任库动态加载)
如果你的 CA 证书会定期更换,可以设计定时任务动态加载 truststore:
// 定时刷新 trustStore
public void refreshTrustStore() throws Exception {
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("ca.jks"), "ca_password".toCharArray());
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(trustStore, null)
.build();
// 重建 HttpClient,或用 HttpClientFactory 管理
}
推荐用 Spring Cloud、Quarkus 等框架的 HttpClientFactory,支持动态刷新。
十四、安全加固措施
-
强制使用 TLSv1.2/1.3
- 服务端配置禁用 TLSv1.0、TLSv1.1。
- 客户端只允许 TLSv1.2/1.3。
-
禁用弱密码套件
- 服务端配置仅允许 AES-GCM、ChaCha20-Poly1305 等强加密套件。
- 客户端默认即可。
-
开启主机名校验和证书链校验
- 生产环境不要用 TrustAllStrategy。
- 使用默认的主机名校验器和信任库。
-
HSTS(HTTP Strict Transport Security)
- 服务端开启,防止降级攻击。
-
定期安全扫描和升级
- 使用 SSL Labs、Nessus、OpenVAS 等工具定期扫描服务端协议和密码套件安全性。
十五、异常处理与重试机制
在实际生产环境,网络抖动或证书变更都可能导致请求失败。推荐集成重试机制:
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
CloseableHttpClient client = HttpClients.custom()
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) // 最多重试3次
.build();
十六、日志与监控
建议集成日志和监控,及时发现 TLS 握手失败、证书过期等问题:
- 开启 Java SSL debug 日志:
-Djavax.net.debug=ssl:handshake - 接入业务监控(如 Prometheus、ELK),监控 HttpClient 请求异常、连接池状态等。
十七、HttpClient 5.x 新特性(TLSv1.3推荐)
HttpClient 5.x 默认支持 TLSv1.3,API 更现代,建议新项目采用。
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(new File("ca.jks"), "ca_password".toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[] {"TLSv1.3", "TLSv1.2"},
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier()
);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
2594

被折叠的 条评论
为什么被折叠?



