Java程序调用外网API时CA问题

前面在配置一个Java应用程序的API调用功能,可当启用此功能参数后,发现API调用没能成功,跟进下后台的日志报错信息,找到如下三行关键栈日志:

1
2
3
4
5
6
7
java.lang.RuntimeException: java.lang.RuntimeException: 
javax.net.ssl.SSLException: java.lang.RuntimeException: 
Unexpected errororithmParameterException: the trustAnchors parameter must be non-empty
Caused by: java.security.InvalidAlgorithmParameterException: 
the trustAnchors parameter must be non-empty
Caused by: java.lang.RuntimeException: Unexpected error: 
java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

原来以为会是常见的问题很容易解决,结果没有想到网上搜索出来的方案有很多而且操作也是比较复杂,然而并不想花费太多时间来验证,所以都没有采用直接就放弃啦。

重新思考可能发生的问题环节,回想起来当时构建Docker镜像的时候,使用的OpenJDK只是JRE解压版本(为了减小Docker镜像的大小),猜测大概是这个有相关的影响,找了其他非Docker环境下可正常运行的节点,首先是使用keytools命令检查了下其JDK里面的安全证书,参考如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts
输入密钥库口令: (直接回车键跳过)

*****************  WARNING WARNING WARNING  *****************
* 存储在您的密钥库中的信息的完整性  *
* 尚未经过验证!  为了验证其完整性, *
* 必须提供密钥库口令。                  *
*****************  WARNING WARNING WARNING  *****************

密钥库类型: JKS
密钥库提供方: SUN

您的密钥库包含 143 个条目

然后再切换回Docker环境中,检查了下解压版本JRE的安全证书,果然这里的密钥库是空的,但至于为何会是空的暂且不讨论,想的办法就是从系统中链接一个密钥库过去。正好使用的CentOS8的操作系统,找到自带的CA证书,直接创建个软链接过去,执行命令参考如下:

1
ln -sf /etc/pki/ca-trust/extracted/java/cacerts $JAVA_HOME/jre/lib/security/cacerts

然后再尝试重新启动Java应用程序,发现API调用服务是可以正常的开始工作啦,这不知道算不算一种幸运的解法。不管怎么说问题是成功解决,所以特此记录并分享一下。🎉

不过需要注意的是,上面提到的CA证书文件并不是所有Linux发行版本系统中默认存在,请根据自己系统的实际情况直接查找。另外也可尝试从其它类似环境中拷贝过来,但需要具体测试才知道能否使用。(亲测是可正常使用,但如果是生产环境得谨慎些。)