在调用服务端接口时出现如下异常 unable to find valid certification path to request target
,从异常信息中可以看到错误是因为找不到证书导致的。解决方案有两个:
- 正常的方案:当然是找到证书并安装证书。
- 暴力的方案:取消证书认证,信任所有请求链接。
第一种方案呢,要先获取服务端证书,然后安装到本地 jdk 的证书库。我们使用 openssl 来获取证书信息,这里我写成了一个 shell 脚本,方便使用。
get_certs_by_domain_port.sh
#!bin/bash
#服务端地址
host=$1
#端口
port=$2
#证书名称
certName=$3
#获取证书
echo "Q"|openssl s_client -connect ${host}:${port} -servername ${host} -showcerts | openssl x509 -outform pem > ${certName}.crt
如果需要循环获取多个证书可以用下面的脚本
#设置域名列表
hosts=(www.baidu.com www.csdn.net www.cnblogs.com)
#设置端口,HTTPS默认端口为443
port=443
#循环获取证书
for host in ${hosts[@]};do
echo "Q"|openssl s_client -connect ${host}:${port} -servername ${host} -showcerts|openssl x509 -outform pem > ${host}.crt
done
执行 sh get_certs_by_domain_port.sh www.baidu.com 443 baidu
即可在当前目录下生成名称为 baidu.crt 的证书。
使用下面的脚本,将获取到的证书导入到 jdk 证书库。
import_jdk_certs.sh
#!/bin/bash
#将证书导入到jdk证书库
#证书别名
alias=$1
#证书文件名
fileName=$2
keytool -import -v -trustcacerts -alias ${alias} -file ${fileName} -storepass changeit -keystore ${JAVA_HOME}/jre/lib/security/cacerts
执行 sh import_jdk_certs.sh baidu baidu.crt
即可将证书导入到 jdk 证书库(需要使用 root 用户,否则会没有权限)。
使用下面的脚本可以查看已经添加到 jdk 证书库里的证书信息,如果输出为空则代表没有找到证书。
cat_jdk_certs.sh
#!/bin/bash
certName=$1
keytool -list -keystore "${JAVA_HOME}/jre/lib/security/cacerts" -storepass changeit |grep ${certName}
执行 sh cat_jdk_certs.sh baidu
查看。
第二种方案:取消证书认证,信任所有请求链接。
/**
* 获取 HttpClient
*
* @param host
* @param path
* @return
* @author 李振华
*/
private static CloseableHttpClient wrapClient(String host, String path) {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
if (host != null && host.startsWith("https://")) {
return sslClient();
} else if (StringUtil.isBlank(host) && path != null && path.startsWith("https://")) {
return sslClient();
}
return httpClient;
}
/**
* 在调用SSL之前需要重写验证方法,取消检测SSL 创建ConnectionManager,添加Connection配置信息
*
* @return HttpClient 支持https
* @author 李振华
*/
private static CloseableHttpClient sslClient() {
try {
// 在调用SSL之前需要重写验证方法,取消检测SSL
AppLogger.debug("在调用SSL之前需要重写验证方法,取消检测SSL");
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
ctx.init(null, new TrustManager[] { trustManager }, null);
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx,
NoopHostnameVerifier.INSTANCE);
// 创建Registry
RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT)
.setExpectContinueEnabled(Boolean.TRUE)
.setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
.setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE).register("https", socketFactory).build();
// 创建ConnectionManager,添加Connection配置信息
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
socketFactoryRegistry);
CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig).build();
return closeableHttpClient;
} catch (KeyManagementException ex) {
throw new RuntimeException(ex);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于