在调用服务端接口时出现如下异常 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); } }
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于