我知道,有许多不同的问题和对这个问题这么多的答案...但我无法理解...
我有:Ubuntu的9.10,桌面AMD64 + NetBeans6.7.1安装“原样”从关闭。 代表。 我需要连接到一些网站通过HTTPS。 为此,我使用Apache的HttpClient的。
从教程中,我读:
“一旦你JSSE正确安装,通过SSL安全HTTP通信应为
简单以纯HTTP通信“和一些例子:
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/");
try {
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine());
} finally {
httpget.releaseConnection();
}
到现在为止,我写这篇文章:
HttpClient client = new HttpClient();
HttpMethod get = new GetMethod("https://mms.nw.ru");
//get.setDoAuthentication(true);
try {
int status = client.executeMethod(get);
System.out.println(status);
BufferedInputStream is = new BufferedInputStream(get.getResponseBodyAsStream());
int r=0;byte[] buf = new byte[10];
while((r = is.read(buf)) > 0) {
System.out.write(buf,0,r);
}
} catch(Exception ex) {
ex.printStackTrace();
}
因此,我有一系列的错误:
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:1627)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:204)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:198)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:994)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:142)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:533)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:471)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:904)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1132)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:643)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
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)
at simpleapachehttp.Main.main(Main.java:41)
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:302)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:205)
at sun.security.validator.Validator.validate(Validator.java:235)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:973)
... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:191)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:297)
... 23 more
我有什么做的,最简单的创建SSL连接? (可能不同时的KeyManager和信托经理等。)
Answer 1:
https://mms.nw.ru使用这显然是不包含在信任管理器的默认设置自签名的证书。
你需要下列之一:
下面是创建一个接受任何一个证书(主要是不值钱的)SSL上下文的一个范例程序:
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLTest {
public static void main(String [] args) throws Exception {
// configure the SSLContext with a TrustManager
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
URL url = new URL("https://mms.nw.ru");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
System.out.println(conn.getResponseCode());
conn.disconnect();
}
private static class DefaultTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}
Answer 2:
https://mms.nw.ru可能使用不是由认证机构颁发的证书。 因此,您需要将证书添加到受信任的Java密钥存储在解释无法找到有效的认证路径请求的目标 :
与启用SSL服务器HTTPS协议上工作的客户端上工作时,你可以得到错误“无法找到有效的认证路径请求的目标”,如果服务器证书不是由证书颁发机构颁发,但自签署或出具私人CMS。
不要惊慌。 所有你需要做的是服务器证书,如果你的客户是用Java编写添加到受信任的Java密钥存储区。 你可能想知道如何,如果你不能访问安装服务器的机器。 有一个简单的程序可以帮助你。 请下载Java程序并运行
% java InstallCert _web_site_hostname_
该程序打开到指定主机的连接,并开始SSL握手。 它打印出的发生,并展示了由服务器所使用的证书错误的异常堆栈跟踪。 现在,它会提示您的证书添加到您的信任密钥库。
如果你已经改变了主意,输入“Q”。 如果你真的想添加的证书,输入“1”,或其他数字添加其他证书,甚至是CA证书,但通常不希望这样做。 一旦你做出你的选择,程序将显示完整的证书,然后将其添加到当前目录中的Java密钥库命名为“jssecacerts”。
要在程序中使用它,无论是配置JSSE使用它作为其信任存储或复制到你的$ JAVA_HOME / JRE / lib / security目录。 如果你希望所有的Java应用程序能够识别该证书作为可信的并不仅仅是JSSE,你也可以覆盖该目录中的cacerts文件。
毕竟是,JSSE将能够完成与主机,您可以通过重新运行程序验证握手。
为了获得更多的细节,你可以检查出Leeland的博客没有更多的“无法找到有效的认证路径请求的目标”
Answer 3:
除了帕斯卡Thivent的正确答案,另一种方式是为了节省从Firefox证书(查看证书- >详细信息- >导出)或openssl s_client
并将其导入到信任存储区。
如果你有一个方法来验证证书时,才应这样做。 如果做不到这一点,做到这一点,你第一次连接时,它至少给你一个错误,如果意外地在后续连接证书的变化。
将其导入信任存储,使用方法:
keytool -importcert -keystore truststore.jks -file servercert.pem
默认情况下,默认的信任存储应该是lib/security/cacerts
,密码应changeit
,看JSSE参考指南了解详情。
如果你不想让该证书在全球范围,但仅限于这些连接,有可能创建SSLContext
吧:
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("/.../truststore.jks");
ks.load(fis, null);
// or ks.load(fis, "thepassword".toCharArray());
fis.close();
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
然后,你需要实现一个如果将其设置为Apache HTTP客户端3.x的SecureProtocolSocketFactory
使用此SSLContext
。 (有例子在这里 )。
的Apache HTTP客户端4.x的(除了最早版本)具有用于传递一个直接支持SSLContext
。
Answer 4:
在Apache的HttpClient 4.5方式:
org.apache.http.ssl.SSLContextBuilder sslContextBuilder = SSLContextBuilder.create();
sslContextBuilder.loadTrustMaterial(new org.apache.http.conn.ssl.TrustSelfSignedStrategy());
SSLContext sslContext = sslContextBuilder.build();
org.apache.http.conn.ssl.SSLConnectionSocketFactory sslSocketFactory =
new SSLConnectionSocketFactory(sslContext, new org.apache.http.conn.ssl.DefaultHostnameVerifier());
HttpClientBuilder httpClientBuilder = HttpClients.custom().setSSLSocketFactory(sslSocketFactory);
httpClient = httpClientBuilder.build();
注: org.apache.http.conn.ssl.SSLContextBuilder
已被弃用 , org.apache.http.ssl.SSLContextBuilder
是新的(注意conn
从后者的包名失踪)。
Answer 5:
从http://hc.apache.org/httpclient-3.x/sslguide.html :
Protocol.registerProtocol("https",
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever.com/");
try {
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine());
} finally {
httpget.releaseConnection();
}
凡MySSLSocketFactory例子可以找到这里 。 它引用TrustManager
,您可以修改信任一切(虽然你必须考虑这个!)
Answer 6:
对于Apache的HttpClient 4.5 +&Java8:
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial((chain, authType) -> true).build();
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(sslContext, new String[]
{"SSLv2Hello", "SSLv3", "TLSv1","TLSv1.1", "TLSv1.2" }, null,
NoopHostnameVerifier.INSTANCE);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();
但是,如果你的HttpClient使用的ConnectionManager寻求连接,例如像这样:
PoolingHttpClientConnectionManager connectionManager = new
PoolingHttpClientConnectionManager();
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
该HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)
没有任何影响 ,该问题没有得到解决。
因为HttpClient的使用指定的ConnectionManager寻求连接和指定的ConnectionManager还没有注册我们的定制SSLConnectionSocketFactory。 为了解决这个问题,应登记在的ConnectionManager的定制SSLConnectionSocketFactory。 正确的代码应该是这样的:
PoolingHttpClientConnectionManager connectionManager = new
PoolingHttpClientConnectionManager(RegistryBuilder.
<ConnectionSocketFactory>create()
.register("http",PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory).build());
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
Answer 7:
一旦你有一个Java证书存储(通过使用上面创建的伟大 InstallCert类),你可以获取Java通过传递“javax.net.ssl.trustStore中”参数在Java启动使用它。
例如:
java -Djavax.net.ssl.trustStore=/path/to/jssecacerts MyClassName
Answer 8:
你可能会遇到与自签名证书的测试另一个问题是这样的:
产生java.io.IOException:HTTPS主机名错误:应该是...
当您试图访问HTTPS URL时出现此错误。 你可能已经安装了服务器证书到你的JRE的密钥库。 但这个错误意味着服务器证书的名称不匹配是在URL中提到的服务器的实际域名。 这当您使用非CA颁发的证书通常发生。
这个例子说明了如何写一个HttpsURLConnection的DefaultHostnameVerifier无视证书服务器名称:
http://www.java-samples.com/showtutorial.php?tutorialid=211
Answer 9:
对于一种能够方便地添加在运行时没有丢弃所有检查信任主机,尝试这里的代码: http://code.google.com/p/self-signed-cert-trust-manager/ 。
Answer 10:
EasySSLProtocolSocketFactory是给我的问题,所以我最终实现我自己的ProtocolSocketFactory。
首先,你需要注册它:
Protocol.registerProtocol("https", new Protocol("https", new TrustAllSSLSocketFactory(), 443));
HttpClient client = new HttpClient();
...
然后实现ProtocolSocketFactory:
class TrustAllSSLSocketFactory implements ProtocolSocketFactory {
public static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(final X509Certificate[] certs, final String authType) {
}
public void checkServerTrusted(final X509Certificate[] certs, final String authType) {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
private TrustManager[] getTrustManager() {
return TRUST_ALL_CERTS;
}
public Socket createSocket(final String host, final int port, final InetAddress clientHost,
final int clientPort) throws IOException {
return getSocketFactory().createSocket(host, port, clientHost, clientPort);
}
@Override
public Socket createSocket(final String host, final int port, final InetAddress localAddress,
final int localPort, final HttpConnectionParams params) throws IOException {
return createSocket(host, port);
}
public Socket createSocket(final String host, final int port) throws IOException {
return getSocketFactory().createSocket(host, port);
}
private SocketFactory getSocketFactory() throws UnknownHostException {
TrustManager[] trustAllCerts = getTrustManager();
try {
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustAllCerts, new SecureRandom());
final SSLSocketFactory socketFactory = context.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
return socketFactory;
} catch (NoSuchAlgorithmException | KeyManagementException exception) {
throw new UnknownHostException(exception.getMessage());
}
}
}
注:这是3.1的HttpClient以及Java 8
Answer 11:
想在这里贴上了答案:
在Apache中的HttpClient 4.5.5
如何处理与Apache 4.5.5客户端无效的SSL证书?
HttpClient httpClient = HttpClients
.custom()
.setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
Answer 12:
此链接说明你一步一步的要求。 如果你是不是真正关心的证书,你可以在下面的链接的过程中进行。
注意您可能要仔细检查,因为你在做什么,这是一个不安全的操作。
Answer 13:
使用InstallCert
生成jssecacerts
文件并执行-Djavax.net.ssl.trustStore=/path/to/jssecacerts
伟大的工作。
Answer 14:
我期运用HttpClient的3.1.X,这对我的作品
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[]{trustManager}, null);
SslContextSecureProtocolSocketFactory socketFactory = new SslContextSecureProtocolSocketFactory(sslContext,false);
Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) socketFactory, 443));//同样会影响到HttpUtils
} catch (Throwable e) {
e.printStackTrace();
}
public class SslContextSecureProtocolSocketFactory implements SecureProtocolSocketFactory {
private SSLContext sslContext;
private boolean verifyHostname;
public SslContextSecureProtocolSocketFactory(SSLContext sslContext, boolean verifyHostname) {
this.verifyHostname = true;
this.sslContext = sslContext;
this.verifyHostname = verifyHostname;
}
public SslContextSecureProtocolSocketFactory(SSLContext sslContext) {
this(sslContext, true);
}
public SslContextSecureProtocolSocketFactory(boolean verifyHostname) {
this((SSLContext)null, verifyHostname);
}
public SslContextSecureProtocolSocketFactory() {
this((SSLContext)null, true);
}
public synchronized void setHostnameVerification(boolean verifyHostname) {
this.verifyHostname = verifyHostname;
}
public synchronized boolean getHostnameVerification() {
return this.verifyHostname;
}
public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException {
SSLSocketFactory sf = this.getSslSocketFactory();
SSLSocket sslSocket = (SSLSocket)sf.createSocket(host, port, clientHost, clientPort);
this.verifyHostname(sslSocket);
return sslSocket;
}
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");
} else {
int timeout = params.getConnectionTimeout();
Socket socket = null;
SSLSocketFactory socketfactory = this.getSslSocketFactory();
if(timeout == 0) {
socket = socketfactory.createSocket(host, port, localAddress, localPort);
} else {
socket = socketfactory.createSocket();
InetSocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
InetSocketAddress remoteaddr = new InetSocketAddress(host, port);
socket.bind(localaddr);
socket.connect(remoteaddr, timeout);
}
this.verifyHostname((SSLSocket)socket);
return socket;
}
}
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
SSLSocketFactory sf = this.getSslSocketFactory();
SSLSocket sslSocket = (SSLSocket)sf.createSocket(host, port);
this.verifyHostname(sslSocket);
return sslSocket;
}
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
SSLSocketFactory sf = this.getSslSocketFactory();
SSLSocket sslSocket = (SSLSocket)sf.createSocket(socket, host, port, autoClose);
this.verifyHostname(sslSocket);
return sslSocket;
}
private void verifyHostname(SSLSocket socket) throws SSLPeerUnverifiedException, UnknownHostException {
synchronized(this) {
if(!this.verifyHostname) {
return;
}
}
SSLSession session = socket.getSession();
String hostname = session.getPeerHost();
try {
InetAddress.getByName(hostname);
} catch (UnknownHostException var10) {
throw new UnknownHostException("Could not resolve SSL sessions server hostname: " + hostname);
}
X509Certificate[] certs = (X509Certificate[])((X509Certificate[])session.getPeerCertificates());
if(certs != null && certs.length != 0) {
X500Principal subjectDN = certs[0].getSubjectX500Principal();
List cns = this.getCNs(subjectDN);
boolean foundHostName = false;
Iterator i$ = cns.iterator();
AntPathMatcher matcher = new AntPathMatcher();
while(i$.hasNext()) {
String cn = (String)i$.next();
if(matcher.match(cn.toLowerCase(),hostname.toLowerCase())) {
foundHostName = true;
break;
}
}
if(!foundHostName) {
throw new SSLPeerUnverifiedException("HTTPS hostname invalid: expected \'" + hostname + "\', received \'" + cns + "\'");
}
} else {
throw new SSLPeerUnverifiedException("No server certificates found!");
}
}
private List<String> getCNs(X500Principal subjectDN) {
ArrayList cns = new ArrayList();
StringTokenizer st = new StringTokenizer(subjectDN.getName(), ",");
while(st.hasMoreTokens()) {
String cnField = st.nextToken();
if(cnField.startsWith("CN=")) {
cns.add(cnField.substring(3));
}
}
return cns;
}
protected SSLSocketFactory getSslSocketFactory() {
SSLSocketFactory sslSocketFactory = null;
synchronized(this) {
if(this.sslContext != null) {
sslSocketFactory = this.sslContext.getSocketFactory();
}
}
if(sslSocketFactory == null) {
sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
}
return sslSocketFactory;
}
public synchronized void setSSLContext(SSLContext sslContext) {
this.sslContext = sslContext;
}
}
Answer 15:
对于HttpClient的,我们可以这样做:
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
String uri = new StringBuilder("url").toString();
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};
HttpClient client = HttpClientBuilder.create().setSSLContext(ctx)
.setSSLHostnameVerifier(hostnameVerifier).build()
Answer 16:
遵循Java 1.7下面给出的指令,创建使用InstallCert.java程序文件的SSL证书。
https://github.com/escline/InstallCert
你必须重新启动Tomcat
Answer 17:
使用DefaultTrustManager大致如下,它在HttpClient的工作般的魅力。 万分感谢!! @Kevin和所有其他贡献者
SSLContext ctx = null;
SSLConnectionSocketFactory sslsf = null;
try {
ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
sslsf = new SSLConnectionSocketFactory(
ctx,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
} catch (Exception e) {
e.printStackTrace();
}
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
Answer 18:
I happened to face the same issue, all of a sudden all my imports were missing. I tried deleting all the contents in my .m2 folder. And trying to re-import everything , but still nothing worked.
Finally what I did was opened the website for which the IDE was complaining that it couldn't download in my browser. And saw the certificate it was using, and saw in my
$ keytool -v -list PATH_TO_JAVA_KEYSTORE
Path to my keystore was /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
that particular certificate was not there.
So all you have to do is put the certificate into the JAVA JVM keystore again.
It can be done using the below command.
$ keytool -import -alias ANY_NAME_YOU_WANT_TO_GIVE -file PATH_TO_YOUR_CERTIFICATE -keystore PATH_OF_JAVA_KEYSTORE
If it asks for password, try the default password 'changeit'
If you get permission error when running the above command.
In windows open it in administration mode.
In mac and unix use sudo.
After you have successfully added the key,
You can view it using :
$ keytool -v -list /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
You can view just the SHA-1 using teh command
$ keytool -list /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
文章来源: How to handle invalid SSL certificates with Apache HttpClient?