javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure问题解决

最近在生产环境调用Https接口出现这个问题javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure,经查询,见到网上大部分答案是替换%JAVA_HOME%\jre\lib\security路径下的两个jar包,local_policy.jar和US_export_policy.jar,由于自己替换后发现依旧出现了这个问题,最终解决了,于是总结一下自己的解决方法以及出现的问题,调用接口我使用的是jdk自带的类,没有使用第三方包。自己出现的问题如下

一、是使用错误,如下图,调用Https接口,应该使用HttpsURLConnection这个来创建连接,而不是HttpURLConnection,

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure问题解决_第1张图片

二、没有设置协议版本,可能使用了默认的版本,Https接口时会进行一个协议版本校验,校验客户端协议的版本和服务端版本是否一致,可以在这个网站查询 https://myssl.com/ 调用地址支持的协议版本,使用的是什么协议,如下图,

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure问题解决_第2张图片

然后设置HttpsURLConnection请求时使用的协议,如下图,第一个红框中SLContext.getInstance("TLSv1.2")中的参数TLSv1.2就是为协议版本,应该对应填写服务器端支持的协议版本。

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure问题解决_第3张图片

然后提供下完成代码

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.*;

public static String insureResponsePost(String url, String param) {
        PrintWriter out = null;
        InputStream is = null;
        BufferedReader br = null;
        String result = "";
        HttpsURLConnection conn = null;
        StringBuffer strBuffer = new StringBuffer();
        try {
            // 创建SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            TrustManager[] tm = {new RecX509TrustManager()};
            // 初始化
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 获取SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL realUrl= new URL(url);
            conn = (HttpsURLConnection) realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestMethod( "POST");
            conn.setConnectTimeout(20000);
            conn.setReadTimeout(300000);
            conn.setRequestProperty("Charset", "UTF-8");
            // 传输数据为json,如果为其他格式可以进行修改
            conn.setRequestProperty( "Content-Type", "application/json; charset=utf-8");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput( true);
            conn.setDoInput( true);
            conn.setUseCaches( false);
            conn.setSSLSocketFactory(ssf);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            log.info(url+"post请求数据"+param);
            out.print(param);
            // flush输出流的缓冲s
            out.flush();
            is = conn.getInputStream();
            br = new BufferedReader( new InputStreamReader(is));
            String line = null;
            while ((line=br.readLine())!= null) {
                strBuffer.append(line);
            }
            result = strBuffer.toString();
            log.info("响应结果"+result);
        } catch (Exception e) {
           log.info("请求异常",e);
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (br != null) {
                    br.close();
                }
                if (conn!= null) {
                    conn.disconnect();
                }
            } catch (IOException ex) {
                log.info("调用异常",ex);
            }
        }
        log.info(url+"post请求响应结果"+result);
        return result;
    }

网上有其他的解决方法,有的是这样设置System.setProperty(“https.protocols”, “TLSv1.2,TLSv1.1,SSLv3”),这种个人感觉还是不太好,这个像是全文设置,可能会影响别的地方,希望能给你提供帮助。

你可能感兴趣的:(java,java)