13

java1.7请求https接口报协议版本错误

 1 year ago
source link: http://xuedingmiao.com/blog/java1.7_protocol_error.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

记录 java 请求接口报 Received fatal alert: protocol_version)错误的处理方法

# 背景

最近公司项目接到合作方反馈某接口出现调不通的问题,错误信息:

Received fatal alert: protocol_version

发现是客户端与服务端 tls 协议版本不一致导致。
服务器使用的是 1.7 版本的 Java,考虑到做 jdk 整体版本升级风险会比较大,所以选择在代码层做绕过。

# 解决方法

在代码中增加绕过的操作,新建如下三个文件:

  • HttpTest 测试类:
package httpClient;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class HttpTest {

    public static void main(String[] args) {
        HttpURLConnection con = null;
        BufferedReader buffer = null;
        StringBuffer resultBuffer = null;

        try {
            URL url = new URL("https://xxx.com/xx");

            // 得到连接对象
            con = (HttpURLConnection) url.openConnection();
            // 设置请求类型
            con.setRequestMethod("POST");
            // 设置Content-Type,此处根据实际情况确定
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            if (con instanceof HttpsURLConnection) {
                // 注释掉之后java1.7会报错
                SSLContext sc = SSLContext.getInstance("TLSv1.2");
                sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
                ((HttpsURLConnection) con).setSSLSocketFactory(sc.getSocketFactory());
                ((HttpsURLConnection) con).setHostnameVerifier(new TrustAnyHostnameVerifier());

            }

            // 允许写出
            con.setDoOutput(true);
            // 允许读入
            con.setDoInput(true);
            // 不使用缓存
            con.setUseCaches(false);
            OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
            out.append("code=ccc");
            out.flush();
            // 得到响应码
            int responseCode = con.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 得到响应流
                InputStream inputStream = con.getInputStream();
                // 将响应流转换成字符串
                resultBuffer = new StringBuffer();
                String line;
                buffer = new BufferedReader(new InputStreamReader(inputStream, "GBK"));
                while ((line = buffer.readLine()) != null) {
                    resultBuffer.append(line);
                }
                System.out.println("result:" + resultBuffer.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • TrustAnyHostnameVerifier 类文件:
package httpClient;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

public class TrustAnyHostnameVerifier implements HostnameVerifier {
    public boolean verify(String hostname, SSLSession session) {
        // 直接Pass
        return true;
    }
}
  • TrustAnyTrustManager 类文件:
package httpClient;

import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class TrustAnyTrustManager implements X509TrustManager {

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[] {};
    }
}

# 测试

测试命令,分别用 jdk 1.7、1.8 进行测试:

// 编译
javac httpClient/HttpTest.java

// 运行
/usr/bin/env /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/bin/java httpClient/HttpTest

/usr/bin/env /Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/bin/java httpClient/HttpTest

如果使用 1.7 则会出现如下结果:

javax.net.ssl.SSLException: Received fatal alert: protocol_version
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
        at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1979)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1086)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1332)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1359)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1343)
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1092)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
        at httpClient.HttpTest.main(HttpTest.java:54)

# 原因分析

1.7 默认使用的 1.1 tls 协议进行握手连接,服务端如果使用 1.2 的tls 则会出现协议不匹配的错误导致握手失败,从而无法正常发出请求。

# 参考资料


Recommend

  • 7
    • guisu.blog.csdn.net 3 years ago
    • Cache

    专栏总结java1:类型和String、反射

    专栏总结java1:类型和String、反射_黄规速博客:学如逆水行舟,不进则退-CSDN博客 ...

  • 14

    微信小程序开发实战(21):发起HTTPS请求_李宁的极客世界bgJBm&nku$q$-CSDN博客在wx对象中有一个request方法,可以发起HTTPS请求。该方法只有一个对象类型参数。该对象支持如下所示。 url:String类型, 必选,开发者服务器接口地址,必须...

  • 10
    • yuanfentiank789.github.io 3 years ago
    • Cache

    mac环境下使用Charles抓包Https请求

    用Charles给Android手机抓包 charles是一款在Mac下常用的截取网络封包工具,对Android Http进行抓包,只要对手机设置代理即可,但对Android Https进行抓包还是破费一些功夫,网上的资料解释的也不清楚,今天在这里总结一下,希望对同...

  • 6
    • muxiaobai.github.io 3 years ago
    • Cache

    SpringBoot之https请求

    SpringBoot之https请求 java

  • 3
    • blog.huoding.com 3 years ago
    • Cache

    使用Fiddler把请求从HTTPS改成HTTP

    跳至主内容区域 火丁笔记 多研究些问题,少谈些主义。

  • 2
    • guolin.blog.csdn.net 3 years ago
    • Cache

    在Android手机上对https请求进行抓包

    在Android手机上对https请求进行抓包

  • 5
    • www.v2ex.com 2 years ago
    • Cache

    折腾老设备的 HTTPS 请求问题

    V2EX  ›  程序员 折腾老设备的 HTTPS 请求问题   monetto · 12 小时 38 分钟前 · 856 次点击...

  • 2
    • blog.wen2go.site 2 years ago
    • Cache

    python请求设置TSL协议版本

    python请求设置TSL协议版本 | wen's blog 有些网站请求出现403等,强制使用tls1.2发包的场景 urllib版本import urllibimport sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv...

  • 4

    tiandy_onvif_http_C++首页、文档和下载 - onvif 接口 http 协议 C++ 版本 - OSCHINA - 中文开源技术交流社区 ...

  • 4

    Java1.8项目纤程实战和性能压测 作者:IT学习道场 2023-04-11 08:35:59 当你的线程池,异步出现性能问题时,请考虑纤程,让你的代码性能数量级的提升,线程池之所以慢,是因为大量的线程频繁的上下文切换,和线程...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK