Apache Httpclient客户端调用TLSv1.2/1.3代码实现

一、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

如果连接成功,说明服务端支持该协议。


八、常见问题与解决办法

  1. 报错:javax.net.ssl.SSLHandshakeException: Received fatal alert: protocol_version

    • 原因:客户端或服务端协议版本不兼容。检查 JDK 版本、服务端配置。
  2. 报错:javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException

    • 原因:证书未被信任。需导入服务端 CA 证书到客户端 truststore。
  3. TLSv1.3不生效?

    • 检查 JDK 版本(需 JDK11+)、服务端配置(如 Nginx/Tomcat/OpenSSL 支持 TLSv1.3)。
  4. 双向认证失败?

    • 检查客户端证书格式、密码是否正确,服务端是否要求客户端证书。

九、完整生产级 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,支持动态刷新。


十四、安全加固措施

  1. 强制使用 TLSv1.2/1.3

    • 服务端配置禁用 TLSv1.0、TLSv1.1。
    • 客户端只允许 TLSv1.2/1.3。
  2. 禁用弱密码套件

    • 服务端配置仅允许 AES-GCM、ChaCha20-Poly1305 等强加密套件。
    • 客户端默认即可。
  3. 开启主机名校验和证书链校验

    • 生产环境不要用 TrustAllStrategy。
    • 使用默认的主机名校验器和信任库。
  4. HSTS(HTTP Strict Transport Security)

    • 服务端开启,防止降级攻击。
  5. 定期安全扫描和升级

    • 使用 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();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猩火燎猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值