今天遇到了个问题,相信很多人都遇到过,使用Httpclient请求https的链接是抛出类似的如下异常
javax.net.ssl.SSLException: hostname in certificate didn't match:www.XXX.com != www.xxx.com
首先来说这个问题产生的原因,根据百度的资料,和实际的情况,我的分析结果是
所请求的网站域名和服务器上的证书中的域名不符,导致请求方域名不匹配的异常
解决这个问题,还要看实际情况,请求的目的是什么,如果是要保证证书的正确,那就不用往下看了,因为下面说的是不需要保证证书正确的情况,想要保证证书正确,只能求助其他的大神,需要导入证书之类的,貌似很高端
我还是直接说下不需要保证证书正确,只要保证正常请求就可以的情况;
首先来说,需要有如下几个关键点
1,SSLContext sslContext
2,X509TrustManager tm
3,SSLConnectionSocketFactory sslsf
这三个我也没有深入研究,第一个我猜是构建那种协议,是SSL还是TLS之类的,第二个完全没想法
第三个就是httpClient链接的时候使用的socekt的工厂了。需要使用到前两个变量作为参数。
来看每个变量的初始化
sslContext= SSLContext.getInstance("SSL");//sslContext= SSLContext.getInstance("TLS");
这里是SSL还是TLS,要看自己的应用情况,我的情况,两种都合适,没所谓,我印象中TLS类似于继承自SSL,不知道区别是哪里,知道的朋友还请赐教
在看tm
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
这个就是new了一个,没做什么操作
接下来需要对sslContext初始化
sslContext.init(null, new TrustManager[] { tm }, null);
这里就是tm的用武之地了,用于初始化sslContext
接下来就是SSLConnectionSocketFactory sslsf
的初始化
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
这里很关键的是第二个参数,个人理解,信任任何证书,说白了也就是不管证书,怎么样都信任,去访问
然后两种方式使我们设置的生效
一种是
Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE).register("https", sslsf).build();
使用registry,注意别把build丢了,这个很关键
另一种方式是直接在构建httpClient的时候设置
HttpClients.custom().setSSLSocketFactory(sslsf).build();
这里的HttpClients.custom()拿到的就是HttpClientBuilder
如果你有这个中间变量,可以直接使用
这样就可以解决问题
顺便说一句,我也尝试过使用类似
httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme(null, null, null));
注意Scheme这里参数需要填的,并非为空,此处仅是举例
这种方式并未成功,而且这种方式使过期的方式
未成功的原因可能是我使用的是CloseableHttpClient,如果使用defaultHttpClient就可以成功,具体原因还有待研究
各位共勉!