公司几个老项目和一个平台好久之前对接过单点登录,突然有人反应说跳转不过去,第一时间和接口方开发确认对方接口有没有变动,得到没有改动的消息。那就很奇怪了,我这边的代码也没有动过,怎么可能突然出问题呢。本地测试后发现请求对方接口报错:javax.net.ssl.SSLException: Received fatal alert: protocol_version,这个错误通常表示客户端和服务器之间的SSL/TLS握手失败,TLSv协议版本不一致。jdk1.7默认使用TLSv1协议,先改成TLSv1.2试试。先是改了tomcat上的配置:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="path/to/keystore" keystorePass="your_keystore_password"
clientAuth="false" sslProtocol="TLSv1.2" />
没有效果,还是报同样的错误,那就在代码上修改,在发送请求的代码之前加上:
System.setProperty("https.protocols", "TLSv1.2");
报错变成了: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。通常是SSL证书校验失败报这个错,那就禁用证书验证试下,用AI生成了一个工具类:
import javax.net.ssl.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class SSLUtilities {
public static void disableCertificateValidation() {
// 创建信任所有证书的TrustManager
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// 安装取消证书验证的TrustManager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// 取消主机名验证
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (NoSuchAlgorithmException | KeyManagementException e) {
// 处理异常
e.printStackTrace();
}
}
}
在创建HttpURLConnection之前,调用SSLUtilities.disableCertificateValidation()方法即可禁用证书验证。
SSLUtilities.disableCertificateValidation();
URL url = new URL("https://example.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// ... 其他代码
重新测试,问题解决。