最近一个项目中Java中用OKHttp/HttpsURLConnection请求一个https的API,出现如下报错:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
用Postman或者浏览器模拟请求,却是正常的,也不是网上查到的所谓的证书问题。
因为实在检查不出来什么原因(也有可能是服务器在防火墙里面被档了什么),索性让OKHttp跳过证书验证,问题解决。
准备如下方法:
/*
* This is very bad practice and should NOT be used in production.
* 最好不要用在生产环境
*/
private static final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
private static final SSLContext trustAllSslContext;
static {
try {
trustAllSslContext = SSLContext.getInstance("SSL");
trustAllSslContext.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException(e);
}
}
public static final SSLSocketFactory trustAllSslSocketFactory = trustAllSslContext.getSocketFactory();
public static OkHttpClient trustAllSslClient(OkHttpClient client) {
OkHttpClient.Builder builder = client.newBuilder();
builder.sslSocketFactory(trustAllSslSocketFactory, (X509TrustManager)trustAllCerts[0]);
//java8以上用的lambda,如果也可以用下面的代码
builder.hostnameVerifier((hostname, session) -> true);
// builder.hostnameVerifier(new HostnameVerifier() {
// @Override
// public boolean verify(String hostname, SSLSession session) {
// return true;
// }
// });
return builder.build();
}
OKHttp的调用方法:
OkHttpClient client = Utils.trustAllSslClient(new OkHttpClient().newBuilder().build()); Request request = new Request.Builder().url(config.getResourceLocation() + "?access_token=" + accessToken).build(); Response response = client.newCall(request).execute(); String string = response.body().string();
如果用HttpsURLConnection这样调用:
URL url = new URL("https://example.com/api/test");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(Utils.trustAllSslSocketFactory);
conn.setHostnameVerifier((s, sslSession) -> true);
文章评论