最近一个项目中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);
文章评论