这么说吧,这个问题真是日了狗了,整了两天才在大家的帮助下解决,虽然深层次的原理还不是很理解,也许不是对所有的这个情况都有用,但是解决方法还是要粘出来希望对其他人有所帮助。
问题描述:首先我有一个webservice既做服务端又做客户端,主要用作接收外部系统的请求,然后请求第三方接口,并把结果处理完成推送给请求方。我自己用客户端模拟发送请求,webservice没有任何问题正常请求第三方接口并返回数据,但是别的系统请求我的webservice,server在调用第三方接口时就会抛出这个异常。令我很费劲,实在不明白二者有什么区别,但很明显与第三方接口的服务端应该没有关系。
叙述有点绕,还是看异常吧。
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:1904)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:279)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:273)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1446)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:209)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:901)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:837)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1023)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1332)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1359)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1343)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1092)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at com.rong360.api.Rong360DataUtils.excutePost(Rong360DataUtils.java:442)
at com.rong360.api.Rong360DataUtils.dataHandlr(Rong360DataUtils.java:82)
at com.glorycube.msgrep.businesshandle.R006Handler.txHandleRequest(R006Handler.java:38)
at com.ws.WsServerHandleDelegate.getMessage(WsServerHandleDelegate.java:93)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.sun.xml.ws.api.server.InstanceResolver$1.invoke(InstanceResolver.java:250)
at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:149)
at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:94)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775)
at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:386)
at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:640)
at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:263)
at com.sun.xml.ws.transport.http.servlet.ServletAdapter.invokeAsync(ServletAdapter.java:218)
at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doGet(WSServletDelegate.java:159)
at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doPost(WSServletDelegate.java:194)
at com.sun.xml.ws.transport.http.servlet.WSServlet.doPost(WSServlet.java:80)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: 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.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1428)
... 55 more
主要原因就是由于访问https的接口,然后会去找安全证书,解决方法如下:
第一步导入安全证书,虽然第三方公司声明不用安全证书,但是由于ssl协议会去找,这个证书最好还是加上。
1、从chrome浏览器中导出 证书的cer格式文件;
第二步:将上面导出的证书导入java中的cacerts证书库
1.查看java目录 which java
/usr/lib/jvm/java7/bin/java
2.查看证书库
keytool -list -keystore /usr/lib/jvm/java7/jre/lib/security/cacerts
此时命令行会提示你输入cacerts证书库密码,
java中cacerts证书库默认密码为changeit,
3.导入证书
keytool -import -alias LL1 -keystore /usr/lib/jvm/java7/jre/lib/security/cacerts -file /hc1/bak/tianji.cer
此时命令行会提示你输入cacerts证书库密码,
java中cacerts证书库默认密码为changeit,然后输入Y确认即可,OK,认证已添加至keystore。
4.可以再次查看证书库,此时已经总数已经多了一个,添加成功。
第三步修改发送请求的代码
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.http.conn.ConnectTimeoutException;
/**
* httpclient https
*
*/
public class HTTPSSecureProtocolSocketFactory implements ProtocolSocketFactory {//SecureProtocolSocketFactory
private SSLContext sslcontext = null;
private SSLContext createSSLContext() {
SSLContext sslcontext = null;
try {
sslcontext = SSLContext.getInstance("SSL");
sslcontext.init(null,
new TrustManager[] { new TrustAnyTrustManager() },
new java.security.SecureRandom());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslcontext;
}
private SSLContext getSSLContext() {
if (null == this.sslcontext) {
this.sslcontext = createSSLContext();
}
return this.sslcontext;
}
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(socket, host,
port, autoClose);
}
public Socket createSocket(String host, int port) throws IOException,
UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(host, port);
}
public Socket createSocket(String host, int port, InetAddress clientHost,
int clientPort) throws IOException, UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(host, port,
clientHost, clientPort);
}
public Socket createSocket(String host, int port, InetAddress localAddress,
int localPort, HttpConnectionParams params) throws IOException,
UnknownHostException, ConnectTimeoutException {
if (params == null) {
throw new IllegalArgumentException("Parameters may not be null");
}
int timeout = params.getConnectionTimeout();
SocketFactory socketfactory = getSSLContext().getSocketFactory();
if (timeout == 0) {
return socketfactory.createSocket(host, port, localAddress,
localPort);
} else {
Socket socket = socketfactory.createSocket();
SocketAddress localaddr = new InetSocketAddress(localAddress,
localPort);
SocketAddress remoteaddr = new InetSocketAddress(host, port);
socket.bind(localaddr);
socket.connect(remoteaddr, timeout);
return socket;
}
}
private static class TrustAnyTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}
}
public static String postByHttps(String url, String body, String contentType) {
String result = "";
Protocol https = new Protocol("https", new HTTPSSecureProtocolSocketFactory(), 443);
Protocol.registerProtocol("https", https);
PostMethod post = new PostMethod(url);
HttpClient client = new HttpClient();
try {
post.setRequestHeader("Content-Type", contentType);
post.setRequestBody(body);
client.executeMethod(post);
result = post.getResponseBodyAsString();
Protocol.unregisterProtocol("https");
return result;
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
return "error";
}