You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring RestTemplate调用HTTPS后端遭遇SSL握手失败问题求助

解决Spring RestTemplate调用HTTPS接口时的PKIX证书验证错误

嘿,这个问题我之前帮同事排查过好多次,核心原因其实很明确:你的JVM默认不信任目标HTTPS服务器的证书,导致SSL握手失败。HTTP接口不需要证书验证环节,所以能正常调用,HTTPS就卡在了证书校验这一步。下面给你几个不同场景下的实用解决方案:

1. 临时跳过证书验证(仅用于测试环境!)

如果只是本地调试或者临时测试,不想折腾证书导入流程,可以让RestTemplate直接跳过SSL证书校验。注意:这个方式绝对不能用于生产环境,会完全暴露SSL的安全风险。

代码示例:

import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

import javax.net.ssl.*;
import java.security.cert.X509Certificate;

public class UnsafeRestTemplateConfig {
    public static RestTemplate createUnsafeRestTemplate() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setHttpClient(createUnsafeHttpClient());
        return new RestTemplate(factory);
    }

    private static CloseableHttpClient createUnsafeHttpClient() {
        try {
            // 创建信任所有证书的TrustManager
            TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {}
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {}
                }
            };

            // 初始化SSL上下文
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            // 构建跳过主机名验证的HttpClient
            return HttpClients.custom()
                    .setSSLSocketFactory(new SSLConnectionSocketFactory(sslSocketFactory,
                            (hostname, session) -> true))
                    .build();
        } catch (Exception e) {
            throw new RuntimeException("Failed to create unsafe RestTemplate", e);
        }
    }
}

使用时直接调用createUnsafeRestTemplate()获取实例即可。

2. 导入证书到JVM信任库(生产环境推荐)

这是生产环境最规范的解决方案,让JVM全局信任目标服务器的证书。步骤如下:

  • 导出目标服务器证书:用浏览器访问目标HTTPS接口,点击地址栏的锁图标,查看证书详情,导出为.cer格式的文件。
  • 导入到JVM信任库:打开终端执行以下命令(替换占位符为你的实际路径):
keytool -importcert -alias my-backend-api -file /path/to/your/cert.cer -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

注意:JDK 11及以上版本的cacerts路径是$JAVA_HOME/lib/security/cacerts,默认密码为changeit。如果是Tomcat等容器运行应用,要确保容器使用的JDK是你导入证书的那一个。

3. 自定义RestTemplate的SSL上下文(灵活适配多场景)

如果不想修改全局JVM信任库,或者需要为不同的RestTemplate配置不同证书,可以自定义SSL上下文,只对当前RestTemplate生效。

代码示例(加载本地证书文件):

import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;

public class CustomSslRestTemplateConfig {
    public static RestTemplate createRestTemplateWithCustomCert() {
        try {
            // 加载本地证书文件
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            FileInputStream certFile = new FileInputStream("/path/to/your/cert.cer");
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null);
            trustStore.setCertificateEntry("my-backend-cert", cf.generateCertificate(certFile));
            certFile.close();

            // 创建带自定义信任库的SSL上下文
            SSLContext sslContext = SSLContexts.custom()
                    .loadTrustMaterial(trustStore, null)
                    .build();

            // 构建HttpClient并设置到RestTemplate
            CloseableHttpClient httpClient = HttpClients.custom()
                    .setSSLContext(sslContext)
                    .build();
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
            return new RestTemplate(factory);
        } catch (Exception e) {
            throw new RuntimeException("Failed to create SSL-enabled RestTemplate", e);
        }
    }
}

简单总结下:测试环境临时调试用方案1,生产环境优先选方案2,需要多证书灵活配置用方案3,根据你的实际场景选就行。

内容的提问来源于stack exchange,提问作者Mainor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:15:19