BlueJ中发起HTTP请求抛出SSLHandshakeException问题求助
BlueJ中HTTP请求SSL握手异常问题解决
问题描述
编写的简单HTTP GET请求程序在BlueJ外部运行正常,但在BlueJ内执行时抛出javax.net.ssl.SSLHandshakeException异常,核心原因是java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty,说明BlueJ自带JDK的信任证书库存在问题。
测试代码
import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class Test2 { private static final String POSTS_API_URL = "https://jsonplaceholder.typicode.com/posts"; public static void main(String[] args) throws IOException, InterruptedException { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .GET() .header("accept", "application/json") .uri(URI.create(POSTS_API_URL)) .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } }
抛出的异常信息
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:956) at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:133) at Test2.main(Test2.java:18) Caused by: javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake at java.net.http/jdk.internal.net.http.common.SSLTube.checkForHandshake(SSLTube.java:595) at java.net.http/jdk.internal.net.http.common.SSLTube$SSLTubeFlowDelegate.checkForHandshake(SSLTube.java:156) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Writer.processData(SSLFlowDelegate.java:866) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Writer$WriterDownstreamPusher.run(SSLFlowDelegate.java:721) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:149) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:207) at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:280) at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:233) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Writer.schedule(SSLFlowDelegate.java:758) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate.resumeActivity(SSLFlowDelegate.java:1068) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate.lambda$executeTasks$3(SSLFlowDelegate.java:1167) at java.net.http/jdk.internal.net.http.HttpClientImpl$DelegatingExecutor.execute(HttpClientImpl.java:177) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate.executeTasks(SSLFlowDelegate.java:1143) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate.doHandshake(SSLFlowDelegate.java:1109) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader.processData(SSLFlowDelegate.java:508) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader$ReaderDownstreamPusher.run(SSLFlowDelegate.java:283) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$LockingRestartableTask.run(SequentialScheduler.java:182) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:149) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$TryEndDeferredCompleter.complete(SequentialScheduler.java:324) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:151) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:207) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1583) Caused by: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty at java.base/sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:97) at java.base/sun.security.validator.Validator.getInstance(Validator.java:173) at java.base/sun.security.ssl.X509TrustManagerImpl.getValidator(X509TrustManagerImpl.java:308) at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrustedInit(X509TrustManagerImpl.java:183) at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:254) at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1296) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1195) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1138) at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:393) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:476) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1273) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1260) at java.base/java.security.AccessController.doPrivileged(AccessController.java:714) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1205) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate.lambda$executeTasks$3(SSLFlowDelegate.java:1148) ... 13 more Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty at java.base/java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200) at java.base/java.security.cert.PKIXParameters.<init>(PKIXParameters.java:120) at java.base/java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:104) at java.base/sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:94) ... 29 more
环境详情
- BlueJ版本:5.4.1
- 构建ID:76ffe5af
- Java版本:21.0.4
- 虚拟机:OpenJDK 64-Bit Server VM 21.0.4+7-LTS(Eclipse Adoptium)
- JavaFX版本:20.0.2+3
- 运行系统:Linux 5.15.0-130-generic(amd64)
解决方案
方案1:修复BlueJ自带JDK的信任证书库
- 找到BlueJ自带JDK的安装路径,通常在BlueJ安装目录下的
jdk文件夹 - 进入
jdk/lib/security目录,检查cacerts文件是否存在或为空 - 如果文件为空或损坏,可从系统已安装的正常JDK中复制
cacerts文件替换它,或使用keytool命令重新导入根证书:
默认keytool -import -alias root -keystore cacerts -file /path/to/root/certificate.crtcacerts密码为changeit
方案2:指定系统JDK运行BlueJ
修改BlueJ的启动配置,让它使用系统中已验证可用的JDK:
- 找到BlueJ的启动脚本(Linux下通常是
bluej或bluej.sh) - 在脚本开头添加
JAVA_HOME环境变量指向系统JDK路径:export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH - 保存后重新启动BlueJ
方案3:代码中忽略SSL证书验证(仅测试环境使用)
不推荐生产环境使用,仅用于临时测试:
修改HttpClient的创建逻辑,添加自定义TrustManager跳过证书验证:
import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.security.SecureRandom; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class Test2 { private static final String POSTS_API_URL = "https://jsonplaceholder.typicode.com/posts"; public static void main(String[] args) throws IOException, InterruptedException { // 创建信任所有证书的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) {} } }; try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new SecureRandom()); HttpClient client = HttpClient.newBuilder() .sslContext(sslContext) .build(); HttpRequest request = HttpRequest.newBuilder() .GET() .header("accept", "application/json") .uri(URI.create(POSTS_API_URL)) .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } catch (Exception e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者Alexander Smirnov
相关产品推荐
相关产品推荐

