「原创声明:保留所有权利,禁止转载」
本人在做接口自动化的过程中,遇到了请求第三方 https 协议请求,在经过了短暂的知识重新学习之后,写完代码执行起来总是遇到一个异常,在用客户端执行请求的时候抛出来的,下面是异常的信息:
Exception in thread "main" 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:2023)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
查阅了很多资料,大部分都说是因为 java 本身安全机制引起的,重新去官网下载 jar 包替换即可。以下是修改方法:
因为 jdk 中 jce 的安全机制导致报的错,要去 oracle 官网下载对应的 jce 包替换 jdk 中的 jce 包。
jce 所在地址: %JAVA_HOME%\jre\lib\security 里的 local_policy.jar,US_export_policy.jar
具体异常教程如下:传送门
在原因的第二种里面,有一个需要校验本身的 TLS 的版本和服务端版本是否一致,我就是在这里出了问题,导致的这个异常。因为我一直用的默认参数去创建新的套接字对象。下面是我用 Charles 拦截的请求的 header 信息:
上面圈起来的地方就是现实的服务器的 TLS 版本,相应地改掉自己代码的中设置版本的地方即可。
下面是我的代码:大多数参考了网上的教程,自己做了一些修改,大同小异。下面是获取 SSLcontext 对象的方法,实现了 X509TrustManager 接口,里面方法不用修改。
/**
* 获取SSL套接字对象 重点重点:设置tls协议的版本
*
* @return
*/
public static SSLContext createIgnoreVerifySSL() {
SSLContext sslContext = null;// 创建套接字对象
try {
sslContext = SSLContext.getInstance("TLSv1.2");//指定TLS版本
} catch (NoSuchAlgorithmException e) {
SourceCode.getInstance().output("创建套接字失败!", e);
}
// 实现X509TrustManager接口,用于绕过验证
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
try {
sslContext.init(null, new TrustManager[] { trustManager }, null);//初始化sslContext对象
} catch (KeyManagementException e) {
SourceCode.getInstance().output("初始化套接字失败!", e);
}
return sslContext;
}
下面是创建 https 协议的 client 的方法,其中用到了连接池的使用:
/**
* 获取https协议请求对象
*
* @return
*/
public static CloseableHttpClient getCloseableHttpsClients() {
// 采用绕过验证的方式处理https请求
SSLContext sslcontext = createIgnoreVerifySSL();
// 设置协议http和https对应的处理socket链接工厂的对象
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext)).build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
HttpClients.custom().setConnectionManager(connManager);
// 创建自定义的httpsclient对象
CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
return client;
}
还有一个继承 httpclient 类,重写 createDefault() 方法来实现请求 https 的,经过实验,对于一些 https 协议是没有问题的。
技术类文章精选
- java 一行代码打印心形
- Linux 性能监控软件 netdata 中文汉化版
- 接口测试代码覆盖率(jacoco)方案分享
- 性能测试框架
- 如何在 Linux 命令行界面愉快进行性能测试
- 图解 HTTP 脑图
- 将 swagger 文档自动变成测试代码
- 五行代码构建静态博客
- 基于 java 的直线型接口测试框架初探
非技术文章精选
TesterHome 为用户提供「保留所有权利,禁止转载」的选项。
除非获得原作者的单独授权,任何第三方不得转载标注了「原创声明:保留所有权利,禁止转载」的内容,否则均视为侵权。
具体请参见TesterHome 知识产权保护协议。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。