httpClient访问https接口报错:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

目录

1. 情景描述:

2. 解决方法:

方法一:换jdk1.8

方法二:在创建SSLConnectionSocketFactory 时指定协议


 

 

参考网址:

请教一个 Apache HttpClient 中 SSLConnectionSocketFactory 的 supportedProtocols 的问题 - V2EX
https://www.v2ex.com/t/615059

记一次HttpClient+jdk8调用SSLv3接口的问题 - 柚子苹果果 - 博客园
https://www.cnblogs.com/LOVE0612/p/13445704.html

HttpClient4.3 关于https 中SSL证书请求问题_游龙YoooLong-CSDN博客_sslconnectionsocketfactory
https://blog.csdn.net/sleeping_/article/details/50500351

 

1. 情景描述:

访问第三方https接口报错:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

开发环境:jdk1.7.0_60 + httpclient4.5.3

第三方接口url:https://posuat1.mercedes-benz-finance.com.cn/EKYC_ELICENSE/e-license

具体报错信息:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:359)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)

。。。。。。。。。。。。。。。。。。。。

2. 解决方法:

方法一:换jdk1.8

     尝试将代码在jdk1.8.0_161 上运行,发现没有报错,可以正常访问上述https网址。

方法二:在创建SSLConnectionSocketFactory 时指定协议

public static CloseableHttpClient createSSLClientDefault(){
				
//    TLSv1 TLSv1.1 TLSv1.2
//    System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");

    try {
	//SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
	// 在JSSE中,证书信任管理器类就是实现了接口X509TrustManager的类。
	//我们可以自己实现该接口,让它信任我们指定的证书。
	// 创建SSLContext对象,并使用我们指定的信任管理器初始化
	//信任所有
	X509TrustManager x509mgr = new X509TrustManager() {
	    //该方法检查客户端的证书,若不信任该证书则抛出异常
	    public void checkClientTrusted(X509Certificate[] xcs, String string) {
	    }
	    //该方法检查服务端的证书,若不信任该证书则抛出异常
	    public void checkServerTrusted(X509Certificate[] xcs, String string) {
	    }
	    //返回受信任的X509证书数组。
	    public X509Certificate[] getAcceptedIssuers() {
		return null;
	    }
	};
		                
	SSLContext sslContext = SSLContext.getInstance("TLS");
//	sslContext.init(null, new TrustManager[] { x509mgr }, null);
	sslContext.init(null, new TrustManager[] { x509mgr }, new java.security.SecureRandom());
	/*
	System.out.println("缺省安全套接字使用的协议: " + sslContext.getProtocol());  
	// 获取SSLContext实例相关的SSLEngine  
	SSLEngine en = sslContext.createSSLEngine();  
	System.out.println("支持的协议: " + Arrays.asList(en.getSupportedProtocols()));  
	System.out.println("启用的协议: " + Arrays.asList(en.getEnabledProtocols()));  
	System.out.println("支持的加密套件: " + Arrays.asList(en.getSupportedCipherSuites()));  
	System.out.println("启用的加密套件: " + Arrays.asList(en.getEnabledCipherSuites()));  
	*/
		                
	创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
//	SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
		                
	SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
	    sslContext, 
	    new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}, 
	    null, 
	    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

//	SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
//	    sslContext, 
//	    new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}, 
//	    null, 
//	    NoopHostnameVerifier.INSTANCE);

//       SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
//           sslContext, 
//           new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}, 
//           null, 
//           NoopHostnameVerifier.INSTANCE);
		                
	//  HttpsURLConnection对象就可以正常连接HTTPS了,无论其证书是否经权威机构的验证,只要实现了接口X509TrustManager的类MyX509TrustManager信任该证书。
	return HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(requestConfig).build();

    } catch (KeyManagementException e) {
	e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
	e.printStackTrace();
    } catch (Exception e) {
	e.printStackTrace();
    }

    // 创建默认的httpClient实例.
    return  HttpClients.createDefault();
}
			

(1)上面的代码中,主要是在 创建   SSLConnectionSocketFactory sslsf  时,指定了协议:

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslContext,
        new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"},
        null,
        NoopHostnameVerifier.INSTANCE);

(2)上面的代码中,有三个创建 SSLConnectionSocketFactory sslsf 的地方(其中有两个被注释掉了),区别在于指定的协议不同,以及最后一个参数不同。但是针对上面的那个https的url,这三种创建方式都能够正常访问。

 

 

你可能感兴趣的:(web,handshake失败,https)