在使用httpclient3.1登陆某https网站的时候,遇到如下异常:
Login failure 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 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593) at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:632) at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123) at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:506) at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114) at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096) at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398) at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397) at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
以下是网上搜到的解决方案,在初始化httpclient实例前加上两行:
ProtocolSocketFactory fcty = new MySecureProtocolSocketFactory(); Protocol.registerProtocol("https", new Protocol("https", fcty, 443)); httpClient = new HttpClient();
MySecureProtocolSocketFactory类:
package com.jingshou; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import org.apache.commons.httpclient.ConnectTimeoutException; import org.apache.commons.httpclient.HttpClientError; import org.apache.commons.httpclient.params.HttpConnectionParams; import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory; import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; public class MySecureProtocolSocketFactory implements SecureProtocolSocketFactory { private SSLContext sslContext = null; /** * Constructor for MySecureProtocolSocketFactory. */ public MySecureProtocolSocketFactory() { } /** * * @return */ private static SSLContext createEasySSLContext() { try { SSLContext context = SSLContext.getInstance("SSL"); context.init(null, new TrustManager[] { new MyX509TrustManager() }, null); return context; } catch (Exception e) { throw new HttpClientError(e.toString()); } } /** * * @return */ private SSLContext getSSLContext() { if (this.sslContext == null) { this.sslContext = createEasySSLContext(); } return this.sslContext; } /* * (non-Javadoc) * * @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String, * int, java.net.InetAddress, int) */ public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException { return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); } /* * (non-Javadoc) * * @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String, * int, java.net.InetAddress, int, * org.apache.commons.httpclient.params.HttpConnectionParams) */ public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException { if (params == null) { throw new IllegalArgumentException("Parameters may not be null"); } int timeout = params.getConnectionTimeout(); if (timeout == 0) { return createSocket(host, port, localAddress, localPort); } else { return ControllerThreadSocketFactory.createSocket(this, host, port, localAddress, localPort, timeout); } } /* * (non-Javadoc) * * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) */ public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return getSSLContext().getSocketFactory().createSocket(host, port); } /* * (non-Javadoc) * * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) */ public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); } }
MyX509TrustManager类:
package com.jingshou; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.X509TrustManager; public class MyX509TrustManager implements X509TrustManager { /* (non-Javadoc) * @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String) */ public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } /* (non-Javadoc) * @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String) */ public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } /* (non-Javadoc) * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() */ public X509Certificate[] getAcceptedIssuers() { return null; } }
经测试最后结果运行良好,具体原理未知......
本文出自"lijingshou"博客,转载请务必保留此出处http://lijingshou.iteye.com/blog/2005425