java REST客户端在调用https时返回handshake_failure

时间:2018-05-02 14:17:43

标签: java rest ssl https

我正在尝试调用HTTPS Web服务,这是我使用的代码,此功能部署在带有OS amazon linux的AWS实例上

public static <T> T postSecureJsonRequest(String url, Object request, Type responseType) throws Exception {

    BufferedReader br;
    HttpsURLConnection con = null;

    try {
        URL obj = new URL(null, url, new sun.net.www.protocol.https.Handler());

        con = (HttpsURLConnection) obj.openConnection();

        con.setReadTimeout(IntegrationConfiguration.getConnectionTimeOut());
        con.setRequestMethod("POST");
        con.setRequestProperty("Content-Type", "application/json");
        con.setRequestProperty("Accept", "application/json");

        con.setDoOutput(true);
        DataOutputStream wr = new DataOutputStream(con.getOutputStream());
        if (request.getClass().equals(String.class)) {
            wr.writeBytes(request + "");

        } else {
            wr.writeBytes(gson.toJson(request));
        }

        wr.flush();
        wr.close();

        if (con.getResponseCode() != 200) {
            throw new Exception(IntegrationConstants.TECHNICAL_ERROR + " "
                    + ("failed : HTTP error code : " + con.getResponseCode() + " from the main server : " + url));
        }

        br = new BufferedReader(new InputStreamReader((con.getInputStream())));
        String inputLine;
        StringBuffer outputResponse = new StringBuffer();

        while ((inputLine = br.readLine()) != null) {
            outputResponse.append(inputLine);
        }

        return (T) gson.fromJson(outputResponse.toString(), responseType);

    } catch (Exception e) {
        throw e;
    } finally {
        if (con != null) {
            con.disconnect();
        }
    }
}

问题是函数总是抛出Exception

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:1989)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1096)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1342)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1369)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1353)
    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:1157)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:259)
at com.wsg.bit.casino.integration.util.IntegrationUtility.postSecureJsonRequest(IntegrationUtility.java:524)

我在这里缺少什么?

编辑:我从服务器获得了这些信息

* TCP_NODELAY set
* Connected to api..... (1xx.2xx.1xx.1xx) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* ALPN, server accepted to use http/1.1
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*   subject: CN=api.....
*   start date: Apr 27 09:29:11 2018 GMT
*   expire date: Jul 26 09:29:11 2018 GMT
*   common name: api.server1.ih.testenv.io
*   issuer: CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US
> GET / HTTP/1.1
> Host: api.server1.ih.testenv.io
> User-Agent: curl/7.53.1
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Server: nginx/1.10.3 (Ubuntu)
< Date: Thu, 03 May 2018 08:43:05 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 39
< Connection: keep-alive
< cache-control: max-age=0, private, must-revalidate
< x-request-id: 2klhbq0t5ahtlndlmc0003k2

修改:当我从其他HTTPS客户端拨打REST服务时,postman就可以了。

1 个答案:

答案 0 :(得分:1)

您需要在java密钥库中导入证书链。如果它们是私有证书,您可以向Web服务所有者索取证书。 如果它们是公共证书,您可以在任何标准浏览器中打开Web服务链接并下载证书链。

请参阅以下链接以进行导入:

How do I find out what keystore my JVM is using?

How to import a .cer certificate into a java keystore?

您还可以创建自定义密钥库并在其中导入证书,并在代码中对其进行配置。

如果您遇到此问题,则可能会遇到hostverification异常。要解决这个问题,您可以插入以下代码。

    javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {

        public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
            return hostname.equals("www.domainname.com");
        }
    });