本地请求第三方接口,出现如下异常、
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
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:747)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
异常原因
本地没有可用的证书,导致SSL校验失败
解决方案
- 安装证书
- 通过代码方式忽略证书(可以临时用,不推荐长期使用,存在安全性问题)
方案2 源码如下
1- 工具类
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SslUtils {
private static void trustAllHttpsCertificates() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new miTM();
trustAllCerts[0] = tm;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
static class miTM implements TrustManager,X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
/**
* 忽略HTTPS请求的SSL证书,必须在openConnection之前调用
* @throws Exception
*/
public static void ignoreSsl() throws Exception{
HostnameVerifier hv = new HostnameVerifier() { //实现自己的脚丫逻辑,这里就直接返回true,不进行校验
public boolean verify(String urlHostName, SSLSession session) {
System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
return true;
}
};
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
}
2-URL请求封装
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import org.apache.commons.io.IOUtils;
public class SslTest {
public String getRequest(String url,int timeOut) throws Exception{
URL u = new URL(url);
if("https".equalsIgnoreCase(u.getProtocol())){
SslUtils.ignoreSsl();
}
URLConnection conn = u.openConnection();
conn.setConnectTimeout(timeOut);
conn.setReadTimeout(timeOut);
return IOUtils.toString(conn.getInputStream());
}
public String postRequest(String urlAddress,String args,int timeOut) throws Exception{
URL url = new URL(urlAddress);
if("https".equalsIgnoreCase(url.getProtocol())){
SslUtils.ignoreSsl();
}
URLConnection u = url.openConnection();
u.setDoInput(true);
u.setDoOutput(true);
u.setConnectTimeout(timeOut);
u.setReadTimeout(timeOut);
OutputStreamWriter osw = new OutputStreamWriter(u.getOutputStream(), "UTF-8");
osw.write(args);
osw.flush();
osw.close();
u.getOutputStream();
return IOUtils.toString(u.getInputStream());
}
public static void main(String[] args) {
try {
SslTest st = new SslTest();
String result = st.getRequest("https://www.baidu.com/", 3000);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.此处具体代码实现
package com.yjp.dubbo.service;
import com.yjp.dubbo.pojp.User;
import javax.net.ssl.HttpsURLConnection;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.io.*;
import java.net.URL;
public class TestConnection {
public static void main(String[] args) throws Exception {
OutputStreamWriter out = null ;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
String url = "https://citic:30466/dsgj/";
File file = new File("D:\\A.txt");
JAXBContext jbt = JAXBContext.newInstance(User.class);
User user=new User();
user.setTRANS_CODE("21000001");
user.setREQ_SSN("J100330000000002018121715130000012300000");
user.setMCHNT_ID("J10033000000000");
user.setMCHNT_USER_ID("test1");
user.setUSER_TYPE("1");
user.setUSER_NM("联调测试");
user.setUSER_ROLE("001001");
user.setSIGN_TYPE("00");
user.setUSER_ID_TYPE("01");
user.setUSER_ID_NO("000013477");
user.setUSER_PHONE("15562632654");
user.setCORP_NM("李先生");
user.setCORP_ID_NO("123456");
user.setUSER_ADD("北京市青年路");
user.setREQ_RESERVED("");
user.setSIGN_INFO("00");
Marshaller ms = jbt.createMarshaller();
ms.marshal(user, file);
in = new BufferedReader(new FileReader("D:\\A.txt"));
int b;
StringBuilder param = new StringBuilder();
while((b=in.read())!=-1){
param.append((char) b);
}
System.out.print(param);
System.out.println("");
System.out.println("-------------------------------------------------------");//此处对url进行post请求
try {
URL realUrl = new URL(url);
if("https".equalsIgnoreCase(realUrl.getProtocol())){
SslUtils.ignoreSsl();
}
// 打开和URL之间的连接
HttpsURLConnection conn = (HttpsURLConnection)realUrl.openConnection();
//设置通用的请求头属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行 否则会抛异常(java.net.ProtocolException: cannot write to a URLConnection if doOutput=false - call setDoOutput(true))
conn.setDoOutput(true);
conn.setDoInput(true);
//获取URLConnection对象对应的输出流并开始发送参数
out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
//添加参数
out.write(param.toString());
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}finally {// 使用finally块来关闭输出流、输入流
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
System.out.println(result.toString());
}
}