将 REST 客户端与 header 一起使用时获取 ssl.SSLHandshakeException 但与 PostMan 配合使用时效果很好

Getting ssl.SSLHandshakeException when using REST client with header but works fine with PostMan

我有一个外部 REST 资源,详细信息如下:

  1. URL:abc.com/orders(域名同https
  2. 我需要将 UserID 作为 HTTP header 传递,键 "user" 值为 "abcd"
  3. 这会 return 一个 JSON 响应

我为此使用以下 Java 代码:

try {

            Client client = Client.create();

            WebResource webResource = client.resource("abc.com/orders");

            ClientResponse response = webResource.header("user", "abcd").accept("application/json")
                    .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();

        }

但是我遇到了异常,尽管它与 PostMan

一起工作正常
com.sun.jersey.api.client.ClientHandlerException: 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
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:155)
    at com.sun.jersey.api.client.Client.handle(Client.java:652)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682)
    at com.sun.jersey.api.client.WebResource.access0(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:509)

我试着搜索了一下,发现我需要从那个 URL 获取证书并添加到 jdk/lib/security 文件夹的某个地方。但我不知道如何进行。

使用 openssl 我得到以下输出:

user>openssl s_client -connect  abc.com:443

CONNECTED(00000214)
7832:error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error:s23_clnt.c:802:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 308 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1531657560
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)

这些是使您的程序运行的说明。顺便说一句,我在 windows,使用 google chrome。

您确实需要证书。

1) 首先,转到url(无论是网站还是restful服务),让我们选择google.com。右键单击页面并单击 "inspect"。

2) 转到安全选项卡。

3) 到达那里后,单击 "view certificate"。

将弹出 window,其中包含站点证书的详细信息。

4) 转到 "certification path" 选项卡。然后双击层次结构中所需的证书。

会弹出一个新的window:

我在本例中选择了名为 "Google trust services..." 的根证书,但您可以选择更具体的证书,例如 "Google Internet Authority G3"。我认为它越具体,它提供的安全性就越高(但我不确定)。

5) 转到 "Details" 选项卡并选择您的证书名称:

6) 点击"Copy To File",然后选择名称和保存位置。我将我的保存在桌面上并将其命名为 "test.cer".

现在您已完成导出证书。接下来,您想将它添加到 jvm 的信任库中。

1) 查看您的应用程序在哪个 JRE 上 运行,例如我的计算机上只有一个 JRE(不包括与 JDK 捆绑在一起的那个)。它位于此处:

存储证书的目标文件是cacerts:

2) 以管理员身份打开 cmd 并执行 cd "C:\Program Files\Java\jre-10.0.1\lib\security"(在我的例子中是 cacerts 的路径)。

3) 发出以下命令:

keytool -import -storepass changeit -noprompt -alias *alias* -keystore cacerts -trustcacerts -file *path_to_certificate*

请注意,别名可以是任何东西,无论您如何称呼您的文件,只要它不与信任库中已有的其他证书的别名冲突即可。

在我的例子中,我发出这个:

4) 您现在可以发出此命令:keytool -list -keystore cacerts -alias *alias* 以确保您的证书已添加。当您发出此命令时,它会询问您的密码。在第三步中,我给你的命令有这个选项:-storepass changeit,所以你的密码将是 changeit.

就我而言,一切都很好。

5) 现在您可以重新启动您的应用程序,它应该可以工作了。有人建议重启电脑,不知道有没有必要

伙计!以上都不需要!!! 只需在 Rest Api 代码之前传递 RestAssured.useRelaxedHTTPSValidation();。 完成!`