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

Java调用REST API时出现SSLHandshakeException异常求助

解决Java调用REST API时的SSLHandshakeException异常

嘿,遇到这个异常别慌!SSLHandshakeException本质就是你的Java程序和目标API服务器在建立加密连接(SSL/TLS)时“谈崩了”——双方没法就加密规则、证书信任达成一致,导致连接建不起来。我结合你代码里提到的两种调用方式(HttpURLConnection和JAX-RS Client),给你分场景讲解决方案:

先搞懂常见触发原因

这个异常最常出现的几个场景:

  • 目标API用了自签名SSL证书(这类证书不在JVM默认的信任证书库cacerts里,JVM会直接拒绝信任)
  • 你的JVM版本太旧,自带的信任证书库没有服务器CA根证书(比如某些新的CA证书没被老版本Java收录)
  • 服务器禁用了你的Java版本支持的SSL协议(比如Java 8默认支持TLS 1.0/1.1/1.2,而服务器只允许TLS 1.3)

分场景解决方法

场景1:用HttpURLConnection调用API(测试环境临时方案)

如果是测试环境,不想折腾证书导入,可以临时跳过SSL验证(注意:生产环境绝对不能这么做,会带来严重安全风险!):

先写一个工具类来禁用SSL验证:

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

public class SSLUtil {
    public static void disableSSLVerification() throws Exception {
        // 创建一个信任所有证书的TrustManager
        TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {}

                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {}
            }
        };

        // 初始化SSL上下文,设置信任管理器
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        // 跳过主机名验证(避免证书域名和请求域名不一致的报错)
        HostnameVerifier allHostsValid = (hostname, session) -> true;
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    }
}

然后在你的请求代码前调用这个工具方法:

public static void main(String[] args) throws Exception {
    // 临时禁用SSL验证(仅测试用)
    SSLUtil.disableSSLVerification();

    URL url = new URL("https://your-target-api-url.com");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    // 后续的请求配置(比如请求方法、请求体等)
    // ...
}

场景2:用JAX-RS ClientBuilder调用API(测试环境临时方案)

如果你用的是JAX-RS的客户端(比如Jersey或RESTEasy),可以这么配置信任所有证书:

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import java.security.cert.X509Certificate;

public class ApiClient {
    public static Client createTrustAllClient() throws Exception {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{
            new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {}

                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {}
            }
        }, new java.security.SecureRandom());

        return ClientBuilder.newBuilder()
                .sslContext(sslContext)
                .hostnameVerifier((hostname, session) -> true)
                .build();
    }

    public static void main(String[] args) throws Exception {
        Client client = createTrustAllClient();
        // 调用API并获取响应
        String response = client.target("https://your-target-api-url.com")
                .request(MediaType.APPLICATION_JSON)
                .get(String.class);
        System.out.println(response);
    }
}

生产环境的正确姿势

上面的临时方案只能用于测试!生产环境必须用安全的方式处理:

  1. 获取目标服务器的SSL证书:可以通过浏览器访问API地址,导出证书(通常是.crt格式)
  2. 将证书导入JVM信任库:使用keytool命令导入到JVM默认的cacerts库中,示例:
    keytool -import -alias api-server-cert -file /path/to/your/cert.crt -keystore $JAVA_HOME/jre/lib/security/cacerts
    
    默认的cacerts密码是changeit
  3. 自定义信任库(可选):如果不想修改全局的cacerts,可以创建自己的信任库,然后在代码中指定:
    import org.apache.http.ssl.SSLContexts;
    // 这里用Apache的SSLContexts工具类,也可以用JDK原生方式
    SSLContext sslContext = SSLContexts.custom()
            .loadTrustMaterial(new File("/path/to/your/custom-truststore.jks"), "your-truststore-password".toCharArray())
            .build();
    Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:03:43