使用 jersey 客户端通过 HTTPS 调用 api 时出现错误 handshake_failure。我已关闭服务器证书有效性检查

Posted

技术标签:

【中文标题】使用 jersey 客户端通过 HTTPS 调用 api 时出现错误 handshake_failure。我已关闭服务器证书有效性检查【英文标题】:I am getting the error handshake_failure when using jersey client to call api with HTTPS. I have turned off the server certificate validity check 【发布时间】:2016-09-15 11:13:12 【问题描述】:

我在使用 jersey 客户端通过 HTTPS 调用 api 时收到 error handshake_failure。 如果该站点以 HTTP 托管,那么它工作正常。 我在使用 HTTPS 时也关闭了服务器证书有效性检查。

@Test
public void GetMember2()
    try
        System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");

        Date today1 = new Date(); // default window is 1 hour
        String stringToday1 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US).format(today1);

        Client client = Client.create(configureClient());

        WebResource webResource = client.resource("https://test.abcd.net/Members/72771583886/promotions?startDate=12122015");

        ClientResponse response = webResource.accept("application/xml")
                .type("application/xml")
                .header("Date", stringToday1)
                .get(ClientResponse.class);

        if (response.getStatus() != 200) 
           throw new RuntimeException("Failed : HTTP error code : "
            + response.getStatus());
        

        String output = response.getEntity(String.class);

        System.out.println("Output from Server .... \n");
        System.out.println(output);

       catch (Exception e) 
        e.printStackTrace();
      


public static ClientConfig configureClient() 
    TrustManager[ ] certs = new TrustManager[ ] 
            new X509TrustManager() 
                public X509Certificate[] getAcceptedIssuers() 
                    return null;
                
                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException 
                
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException 
                
            
    ;
    SSLContext ctx = null;
    try 
        ctx = SSLContext.getInstance("TLS");
        ctx.init(null, certs, new SecureRandom());
     catch (java.security.GeneralSecurityException ex) 
    
    HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());

    ClientConfig config = new DefaultClientConfig();
    try 
        config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(
            new HostnameVerifier() 
                public boolean verify(String hostname, SSLSession session) 
                    return true;
                
            , 
            ctx
        ));
     catch(Exception e) 
    

    return config;

错误:com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException:收到致命警报: 握手失败在 com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:155) 在 com.sun.jersey.api.client.Client.handle(Client.java:652) 在 com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) 在 com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) 在 com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:509) 在 Frameworks.Prototype2.GetLoyaltyMember2(Prototype2.java:106) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(未知来源)在 java.lang.reflect.Method.invoke(未知来源)

【问题讨论】:

当我使用 HTTPS 连接调用 api 时,以下代码在 C#/Visual Studio 中完美运行。我无法在 Java 中找到类似的东西。 //关闭服务器证书有效性检查 ServicePointManager.ServerCertificateValidationCallback = delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) return true; ; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 |安全协议类型.Tls11 |安全协议类型.Tls; 您也可以从较旧的 JDK 版本中获取此错误(可能来自 JDK 中包含的不同/较旧的 TLS 支持)。例如,使用 1.7 执行的相同代码会出现此错误,但 1.8 不会。 【参考方案1】:

暂时打开 Java 网络库的调试以查看您遇到的 SSL 错误类型:-Djavax.net.debug=all

【讨论】:

【参考方案2】:

握手可能因各种原因而失败,而不仅仅是证书验证问题。 它可能用于:

不共享相同的密码套件 不共享 SSL 版本 证书验证 打算更改 TLS 版本 其他

找出问题所在的最佳方法是安装 Wireshark 并查看握手消息。然后根据从服务器发送到客户端的 SSL 警报消息,您可以获得有关 SSL 握手失败的更多信息,具体发生在哪里。

此链接也可能有帮助:Received fatal alert: handshake_failure through SSLHandshakeException

【讨论】:

当我使用 HTTPS 连接调用 api 时,以下代码在 C#/Visual Studio 中完美运行。我无法在 Java 中找到类似的东西。 //关闭服务器证书有效性检查 ServicePointManager.ServerCertificateValidationCallback = delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) return true; ; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; @user6332513,好的,只需使用wireshark或其他工具了解为什么会出现SSL警报。它是什么警报类型。【参考方案3】:

从oracle网站下载jce_policy-8.zip并解压得到以下2个JAR-files。

local_policy.jar US_export_policy.jar

在您的 JVM 中更新上述 2 个策略,即在我的情况下为 /Library/Java/JavaVirtualMachines/jdk1.8.0_102.jdk/Contents/Home/jre/lib/security

它应该可以工作。

【讨论】:

以上是关于使用 jersey 客户端通过 HTTPS 调用 api 时出现错误 handshake_failure。我已关闭服务器证书有效性检查的主要内容,如果未能解决你的问题,请参考以下文章

Jersey jax.rs 客户端 2.5 遵循从 HTTP 到 HTTPS 的重定向

带有 Jersey 客户端版本 2.2 的 Restful WebService 调用

使用Jersey的Http DELETE参数

使用ClientResponse发布时,Jersey客户端MessageBodyProviderNotFoundException

Jersey 2 - 带有 .target HTTPS

从 Jersey REST 客户端调用时出现 405 错误代码