Apache HttpClient 在 macOS 上失败并显示 Java 11
Apache HttpClient failing with Java 11 on macOS
我正在尝试将我的代码从 Java 8 移动到 Java 11,此代码...
private static String readMultiHttpsUrlResultAsString(List<String> mbRecordingIds, String level) throws Exception
{
String result = "";
class NaiveTrustStrategy implements TrustStrategy
{
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
return true;
}
};
SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(new NaiveTrustStrategy())
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(sslcontext))
.build();
StringBuilder sb = new StringBuilder("?recording_ids=");
for(String next:mbRecordingIds)
{
sb.append(next + ";");
}
sb.setLength(sb.length() - 1);
try
{
String url = "https://acousticbrainz.org/api/v1"+level+sb;
HttpGet httpget = new HttpGet(url);
try (CloseableHttpResponse response = httpclient.execute(httpget);)
{
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode!=HttpURLConnection.HTTP_OK)
{
return "";
}
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity);
EntityUtils.consume(entity);
}
}
finally
{
httpclient.close();
}
return result;
}
}
在 MacOS 上使用 (AdoptOpenJdk) Java 11.0.6 失败,
SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(new NaiveTrustStrategy())
.build();
它 运行 在 Windows 上没有问题(也使用 AdoptOpenJdk Java 11.0.6)。一个区别是 Windows 版本使用从 jdk 和 jlink 构建的缩减 jre,而 MacOS 版本使用 AdoptOpenJDk jre 构建。 MacOS 构建是使用 AppBundler
的 InfiniteKinds 分支创建的
这是堆栈跟踪:
java.lang.NoClassDefFoundError: Could not initialize class sun.security.ssl.SSLContextImpl$TLSContext
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
at java.base/java.security.Provider$Service.getImplClass(Provider.java:1848)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1824)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at org.apache.http.ssl.SSLContextBuilder.build(SSLContextBuilder.java:269)
at com.jthink.songkong.analyse.acousticbrainz.AcousticBrainz.readMultiHttpsUrlResultAsString(AcousticBrainz.java:409)
at com.jthink.songkong.analyse.acousticbrainz.AcousticBrainz.readLowLevelData(AcousticBrainz.java:373)
我正在使用 Apache Httpclient 4.5.3 并使用此库,因为我从需要使用 ssl 的 Web 服务获取数据。
更新
我从下面的答案中将示例测试添加到我的源代码中,并修改了我的构建以在应用程序为 运行 时将其作为开始 class 并且它给了我这个堆栈跟踪(当捆绑包为 运行 从命令行使用 open
使用 java 运行 由 infinitekind appbundler 嵌入到包中的时间)
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.base/javax.crypto.Cipher.getInstance(Unknown Source)
at java.base/sun.security.ssl.JsseJce.getCipher(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.isTransformationAvailable(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.<init>(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.<clinit>(Unknown Source)
at java.base/sun.security.ssl.CipherSuite.<clinit>(Unknown Source)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(Unknown Source)
at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(Unknown Source)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Unknown Source)
at java.base/java.security.Provider$Service.getImplClass(Unknown Source)
at java.base/java.security.Provider$Service.newInstance(Unknown Source)
at java.base/sun.security.jca.GetInstance.getInstance(Unknown Source)
at java.base/sun.security.jca.GetInstance.getInstance(Unknown Source)
at java.base/javax.net.ssl.SSLContext.getInstance(Unknown Source)
at org.apache.http.ssl.SSLContextBuilder.build(SSLContextBuilder.java:389)
at Example.main(Example.java:23)
Caused by: java.lang.SecurityException: Can not initialize cryptographic mechanism
at java.base/javax.crypto.JceSecurity.<clinit>(Unknown Source)
... 17 more
Caused by: java.lang.SecurityException: Can't read cryptographic policy directory: unlimited
at java.base/javax.crypto.JceSecurity.setupJurisdictionPolicies(Unknown Source)
at java.base/javax.crypto.JceSecurity.run(Unknown Source)
at java.base/javax.crypto.JceSecurity.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Native Method)
... 18 more
这与我以前的有所不同,但也许这是根本原因或者这是误导?
而如果我只是 运行 java -jar songkong6.9.jar
它 运行s 示例并打印出 Loaded 没有错误,如果我指定完整来自 /Library/Java 的路径它也适用于所有情况(Java 11/Java 14/JDk 和 JRE)
更新
根据下面的回答,我取得了一些进步。
安装在 MacOS 上的 JRE 包含一个 conf
文件夹,当使用 InfiniteKinds appbundler 将 JRE 添加到我的包 (SongKong) 时,它没有 conf 文件夹。它确实有一个包含 default.policy
的 lib/security 文件夹,但这似乎还不够。
pauls-Mac-mini:Home paul$ ls -lR lib/security
total 704
-rw-r--r-- 1 paul admin 1253 22 Apr 14:56 blacklisted.certs
-rw-r--r-- 1 paul admin 103147 22 Apr 14:56 cacerts
-rw-r--r-- 1 paul admin 8979 22 Apr 16:01 default.policy
-rw-r--r-- 1 paul admin 233897 22 Apr 14:56 public_suffix_list.dat
如果我手动将 conf 文件夹从已安装的 JRE 复制到 java 插件的 Home 文件夹,则在安装构建包后
例如
/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home
location 然后示例代码和我的原始代码在 运行 来自 bundle 时都可以正常工作。
此外,它似乎正在寻找的是无限文件夹及其内容(这两个文件实际上是相同的),所以如果我删除一些文件,我会留下
pauls-Mac-mini:Home paul$ pwd
/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home
pauls-Mac-mini:Home paul$ ls -lR conf
total 0
drwxr-xr-x 3 paul admin 96 22 Apr 15:14 security
conf/security:
total 0
drwxr-xr-x 3 paul admin 96 22 Apr 15:22 policy
conf/security/policy:
total 0
drwxr-xr-x 4 paul admin 128 22 Apr 15:28 unlimited
conf/security/policy/unlimited:
total 16
-rw-r--r-- 1 paul admin 146 22 Apr 15:06 default_US_export.policy
-rw-r--r-- 1 paul admin 193 22 Apr 15:06 default_local.policy
然后它继续工作。
问题(除了为什么它不能开箱即用)是我假设我无法将文件复制到这个位置以用于强化 运行time 应用程序所以我需要将这些策略文件存储在其他地方以便它们可以作为 appbundler 构建的一部分安装。因此,作为测试,我已将 conf
文件夹重命名为 conf.old
文件夹,并将以下参数添加到 bundle
<string>-Djava.security.policy=/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home/conf.old/security/policy/unlimited/default_local.policy</string>
或替换而不是附加策略文件
<string>-Djava.security.policy==/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home/conf.old/security/policy/unlimited/default_local.policy</string>
但它不起作用,我尝试了各种值,但没有任何效果。唯一可行的是将它留在 conf 子文件夹中,然后我是否传递此参数都没有关系。 (我还尝试将 -Dsecurity.manager
添加为另一个选项,但这只会导致有关日志记录权限的新错误。)
我已经在 Spring Tools Suite 4、AdoptedOpenJDK Java 11.0.6、macOS catalina 10.15.4 和 Maven 3.8.1
上测试了代码
我提取了导致问题的部分代码。
Example.java
:
package com.example;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import org.apache.http.ssl.TrustStrategy;
class NaiveTrustStrategy implements TrustStrategy {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}
public class Example {
public static void main(String... args) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(new NaiveTrustStrategy())
.build();
System.out.println("Loaded");
}
}
注:我拍了javax.net.ssl.SSLContext。
pom.xml :
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>Test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<!-- <target>11</target> <source>11</source> -->
<verbose>true</verbose>
<fork>true</fork>
<executable>
/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home/bin/javac
</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>
输出(用于测试):无错误
我看过这个 link : https://github.com/TheInfiniteKind/appbundler/
请将 JDK/JRE 改为指向 11。
如果问题仍然存在,请下载最新的 appbundler
并再次尝试 运行。
来自 Oracle 文档 (https://www.oracle.com/java/technologies/javase-jce-all-downloads.html):
Current versions of the JDK do not require these policy files.
JDK 9 and later ship with, and use by default, the unlimited policy
files.
The unlimited policy files are required by JDK 8, 7 and 6 only.
You can download these policy files from the documentation link above.
我认为政策文件可能丢失或其他一些问题。请验证。
最终在 Anish 的帮助下解决了丢失策略文件的问题,并且只是使用 AppBunder 构建的捆绑包的问题。
jdk 代码似乎确实需要 JRE 中的 conf
文件夹,OpenJDk 中有一个,但一次都没有使用 AppBundler 捆绑到我的应用程序中。所以我下载了最新的 AppBundler src 代码并重建了它,重建了我的 appbundle 并且它被修复了,现在包含了 conf 文件夹并且应用程序运行没有错误。
我正在尝试将我的代码从 Java 8 移动到 Java 11,此代码...
private static String readMultiHttpsUrlResultAsString(List<String> mbRecordingIds, String level) throws Exception
{
String result = "";
class NaiveTrustStrategy implements TrustStrategy
{
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
return true;
}
};
SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(new NaiveTrustStrategy())
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(sslcontext))
.build();
StringBuilder sb = new StringBuilder("?recording_ids=");
for(String next:mbRecordingIds)
{
sb.append(next + ";");
}
sb.setLength(sb.length() - 1);
try
{
String url = "https://acousticbrainz.org/api/v1"+level+sb;
HttpGet httpget = new HttpGet(url);
try (CloseableHttpResponse response = httpclient.execute(httpget);)
{
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode!=HttpURLConnection.HTTP_OK)
{
return "";
}
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity);
EntityUtils.consume(entity);
}
}
finally
{
httpclient.close();
}
return result;
}
}
在 MacOS 上使用 (AdoptOpenJdk) Java 11.0.6 失败,
SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(new NaiveTrustStrategy())
.build();
它 运行 在 Windows 上没有问题(也使用 AdoptOpenJdk Java 11.0.6)。一个区别是 Windows 版本使用从 jdk 和 jlink 构建的缩减 jre,而 MacOS 版本使用 AdoptOpenJDk jre 构建。 MacOS 构建是使用 AppBundler
这是堆栈跟踪:
java.lang.NoClassDefFoundError: Could not initialize class sun.security.ssl.SSLContextImpl$TLSContext
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:315)
at java.base/java.security.Provider$Service.getImplClass(Provider.java:1848)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1824)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at org.apache.http.ssl.SSLContextBuilder.build(SSLContextBuilder.java:269)
at com.jthink.songkong.analyse.acousticbrainz.AcousticBrainz.readMultiHttpsUrlResultAsString(AcousticBrainz.java:409)
at com.jthink.songkong.analyse.acousticbrainz.AcousticBrainz.readLowLevelData(AcousticBrainz.java:373)
我正在使用 Apache Httpclient 4.5.3 并使用此库,因为我从需要使用 ssl 的 Web 服务获取数据。
更新
我从下面的答案中将示例测试添加到我的源代码中,并修改了我的构建以在应用程序为 运行 时将其作为开始 class 并且它给了我这个堆栈跟踪(当捆绑包为 运行 从命令行使用 open
使用 java 运行 由 infinitekind appbundler 嵌入到包中的时间)
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.base/javax.crypto.Cipher.getInstance(Unknown Source)
at java.base/sun.security.ssl.JsseJce.getCipher(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.isTransformationAvailable(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.<init>(Unknown Source)
at java.base/sun.security.ssl.SSLCipher.<clinit>(Unknown Source)
at java.base/sun.security.ssl.CipherSuite.<clinit>(Unknown Source)
at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(Unknown Source)
at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(Unknown Source)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Unknown Source)
at java.base/java.security.Provider$Service.getImplClass(Unknown Source)
at java.base/java.security.Provider$Service.newInstance(Unknown Source)
at java.base/sun.security.jca.GetInstance.getInstance(Unknown Source)
at java.base/sun.security.jca.GetInstance.getInstance(Unknown Source)
at java.base/javax.net.ssl.SSLContext.getInstance(Unknown Source)
at org.apache.http.ssl.SSLContextBuilder.build(SSLContextBuilder.java:389)
at Example.main(Example.java:23)
Caused by: java.lang.SecurityException: Can not initialize cryptographic mechanism
at java.base/javax.crypto.JceSecurity.<clinit>(Unknown Source)
... 17 more
Caused by: java.lang.SecurityException: Can't read cryptographic policy directory: unlimited
at java.base/javax.crypto.JceSecurity.setupJurisdictionPolicies(Unknown Source)
at java.base/javax.crypto.JceSecurity.run(Unknown Source)
at java.base/javax.crypto.JceSecurity.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Native Method)
... 18 more
这与我以前的有所不同,但也许这是根本原因或者这是误导?
而如果我只是 运行 java -jar songkong6.9.jar
它 运行s 示例并打印出 Loaded 没有错误,如果我指定完整来自 /Library/Java 的路径它也适用于所有情况(Java 11/Java 14/JDk 和 JRE)
更新 根据下面的回答,我取得了一些进步。
安装在 MacOS 上的 JRE 包含一个 conf
文件夹,当使用 InfiniteKinds appbundler 将 JRE 添加到我的包 (SongKong) 时,它没有 conf 文件夹。它确实有一个包含 default.policy
的 lib/security 文件夹,但这似乎还不够。
pauls-Mac-mini:Home paul$ ls -lR lib/security
total 704
-rw-r--r-- 1 paul admin 1253 22 Apr 14:56 blacklisted.certs
-rw-r--r-- 1 paul admin 103147 22 Apr 14:56 cacerts
-rw-r--r-- 1 paul admin 8979 22 Apr 16:01 default.policy
-rw-r--r-- 1 paul admin 233897 22 Apr 14:56 public_suffix_list.dat
如果我手动将 conf 文件夹从已安装的 JRE 复制到 java 插件的 Home 文件夹,则在安装构建包后
例如
/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home
location 然后示例代码和我的原始代码在 运行 来自 bundle 时都可以正常工作。
此外,它似乎正在寻找的是无限文件夹及其内容(这两个文件实际上是相同的),所以如果我删除一些文件,我会留下
pauls-Mac-mini:Home paul$ pwd
/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home
pauls-Mac-mini:Home paul$ ls -lR conf
total 0
drwxr-xr-x 3 paul admin 96 22 Apr 15:14 security
conf/security:
total 0
drwxr-xr-x 3 paul admin 96 22 Apr 15:22 policy
conf/security/policy:
total 0
drwxr-xr-x 4 paul admin 128 22 Apr 15:28 unlimited
conf/security/policy/unlimited:
total 16
-rw-r--r-- 1 paul admin 146 22 Apr 15:06 default_US_export.policy
-rw-r--r-- 1 paul admin 193 22 Apr 15:06 default_local.policy
然后它继续工作。
问题(除了为什么它不能开箱即用)是我假设我无法将文件复制到这个位置以用于强化 运行time 应用程序所以我需要将这些策略文件存储在其他地方以便它们可以作为 appbundler 构建的一部分安装。因此,作为测试,我已将 conf
文件夹重命名为 conf.old
文件夹,并将以下参数添加到 bundle
<string>-Djava.security.policy=/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home/conf.old/security/policy/unlimited/default_local.policy</string>
或替换而不是附加策略文件
<string>-Djava.security.policy==/Applications/SongKong.app/Contents/PlugIns/adoptopenjdk-11.jre/Contents/Home/conf.old/security/policy/unlimited/default_local.policy</string>
但它不起作用,我尝试了各种值,但没有任何效果。唯一可行的是将它留在 conf 子文件夹中,然后我是否传递此参数都没有关系。 (我还尝试将 -Dsecurity.manager
添加为另一个选项,但这只会导致有关日志记录权限的新错误。)
我已经在 Spring Tools Suite 4、AdoptedOpenJDK Java 11.0.6、macOS catalina 10.15.4 和 Maven 3.8.1
上测试了代码我提取了导致问题的部分代码。
Example.java
:
package com.example;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import org.apache.http.ssl.TrustStrategy;
class NaiveTrustStrategy implements TrustStrategy {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}
public class Example {
public static void main(String... args) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(new NaiveTrustStrategy())
.build();
System.out.println("Loaded");
}
}
注:我拍了javax.net.ssl.SSLContext。
pom.xml :
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>Test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<!-- <target>11</target> <source>11</source> -->
<verbose>true</verbose>
<fork>true</fork>
<executable>
/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home/bin/javac
</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>
输出(用于测试):无错误
我看过这个 link : https://github.com/TheInfiniteKind/appbundler/
请将 JDK/JRE 改为指向 11。
如果问题仍然存在,请下载最新的 appbundler
并再次尝试 运行。
来自 Oracle 文档 (https://www.oracle.com/java/technologies/javase-jce-all-downloads.html):
Current versions of the JDK do not require these policy files.
JDK 9 and later ship with, and use by default, the unlimited policy files.
The unlimited policy files are required by JDK 8, 7 and 6 only.
You can download these policy files from the documentation link above.
我认为政策文件可能丢失或其他一些问题。请验证。
最终在 Anish 的帮助下解决了丢失策略文件的问题,并且只是使用 AppBunder 构建的捆绑包的问题。
jdk 代码似乎确实需要 JRE 中的 conf
文件夹,OpenJDk 中有一个,但一次都没有使用 AppBundler 捆绑到我的应用程序中。所以我下载了最新的 AppBundler src 代码并重建了它,重建了我的 appbundle 并且它被修复了,现在包含了 conf 文件夹并且应用程序运行没有错误。