1. 踩坑經歷
最近做了個需求,需要調用第三方接口獲取數據,在聯調時一直失敗,代碼拋出javax.net.ssl.SSLHandshakeException
異常,
具體錯誤信息如下所示:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
2.原因分析
因為調用第三方接口的代碼是復用項目中原有的工具類(基于httpclient封裝),所以在確認完傳參沒問題后,第一時間排除了編碼問題。
然后開始懷疑第三方提供的接口地址(因為竟然是IP+端口訪問),在和第三方確認沒有域名訪問后,在瀏覽器里輸入第三方的接口地址,發現證書有問題:
又使用Postman調用第三方接口,也是失敗,提示自簽名證書:
通過以上分析,可以發現出現該問題的根本原因是Java客戶端不信任目標服務器的SSL證書,比如這個第三方使用的自簽名證書。
3.解決方案
解決方案一般有2種,第1種方案是將服務器證書導入Java信任庫,第2種方案是繞過SSL驗證,這里采用第2種方案。
首先,新建HttpClient工具類:
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;public class HttpClientUtils {public static CloseableHttpClient createIgnoreCertClient() throws NoSuchAlgorithmException, KeyManagementException {SSLContext sslContext = SSLContext.getInstance("SSL");sslContext.init(null, new TrustManager[]{new X509TrustManager() {@Overridepublic X509Certificate[] getAcceptedIssuers() {return null;}@Overridepublic void checkClientTrusted(X509Certificate[] certs, String authType) {}@Overridepublic void checkServerTrusted(X509Certificate[] certs, String authType) {}}}, new java.security.SecureRandom());SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();}
}
然后將原來聲明httpClient的代碼改為如下所示:
CloseableHttpClient httpClient = HttpClientUtils.createIgnoreCertClient();
注意事項:
確保項目中引入了httpclient依賴:
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency>