Java HttpClient With SSL – 带SSL的Java HttpClient

最后修改: 2022年 5月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll explore how to use the Java HttpClient to connect to HTTPS URLs. We’ll also learn how to use the client with URLs that don’t have a valid SSL certificate.

在本教程中,我们将探讨如何使用Java HttpClient连接到HTTPS URLs。我们还将学习如何在没有有效SSL证书的URL上使用该客户端。

In older versions of Java, we preferred to use libraries like Apache HTTPClient and OkHttp to connect to a server. In Java 11, an improved HttpClient library was added to the JDK. Let’s explore how to use it to call a service over SSL.

在旧版本的Java中,我们倾向于使用Apache HTTPClient和OkHttp等库来连接到服务器。在Java 11中,一个改进的HttpClient库被添加到JDK中。让我们探讨一下如何使用它来通过SSL调用服务。

2. Calling an HTTPS URL Using the Java HttpClient

2.使用Java HttpClient调用一个HTTPS URL

We’ll use test cases to run the client code. For testing purposes, we’ll use an existing URL that runs on HTTPS.

我们将使用测试案例来运行客户端的代码。为了测试目的,我们将使用一个在HTTPS上运行的现有URL。

Let’s write code to set up the client and call the service:

让我们编写代码来设置客户端并调用服务。

HttpClient httpClient = HttpClient.newHttpClient();
    
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://www.google.com/"))
  .build();

HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

Here, we first created a client using the HttpClient.newHttpClient() method. Then, we created a request and set the URL of the service we’re going to hit. Finally, we sent the request using the HttpClient.send() method and collected the response – a HttpResponse object containing the response body as a String.

在这里,我们首先使用HttpClient.newHttpClient() 方法创建了一个客户端。然后,我们创建了一个请求,并设置了我们要打的服务的URL。最后,我们使用HttpClient.send()方法发送请求,并收集响应–一个HttpResponse对象,包含作为字符串的响应体。

When we put the above code in a test case and perform the below assertion, we’ll observe that it passes:

当我们把上面的代码放在测试用例中并执行下面的断言时,我们会观察到它通过了。

assertEquals(200, response.statusCode());

3. Calling an Invalid HTTPS URL

3.调用一个无效的HTTPS URL

Now, let’s change the URL to another one that doesn’t have a valid SSL certificate. We can do so by changing the request object:

现在,让我们把这个URL改为另一个没有有效SSL证书的URL。我们可以通过改变请求对象来做到这一点。

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://www.testingmcafeesites.com/"))
  .build();

When we run the test again, we get the below error:

当我们再次运行测试时,我们得到以下错误。

Caused by: java.security.cert.CertificateException: No subject alternative DNS name matching www.testingmcafeesites.com found.
  at java.base/sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:212)
  at java.base/sun.security.util.HostnameChecker.match(HostnameChecker.java:103)

This is because the URL doesn’t have a valid SSL certificate.

这是因为该URL没有一个有效的SSL证书。

4. Bypassing SSL Certificate Verification

4.绕过SSL证书验证

To resolve the error we got above, let’s look at a solution to bypass SSL certificate verification.

为了解决上面得到的错误,让我们看看绕过SSL证书验证的解决方案。

In Apache HttpClient, we could modify the client to bypass certificate verification. However, we can’t do that with the Java HttpClient. We’ll have to rely on making changes to the JVM to disable hostname verification.

在Apache HttpClient中,我们可以修改客户端以绕过证书验证。然而,在Java HttpClient中,我们不能这样做。我们将不得不依靠对JVM的修改来禁用主机名验证。

One way to do this is to import the website’s certificate into the Java KeyStore. This is a common practice and is a good option if there are a small number of internal, trusted websites.

一种方法是将网站的证书导入到Java KeyStore中。这是一种常见的做法,如果有少量的内部受信任的网站,这是一个不错的选择。

However, this can become tiresome if there are a large number of websites or too many environments to manage. In this case, we can use the property jdk.internal.httpclient.disableHostnameVerification to disable hostname verification.

然而,如果有大量的网站或有太多的环境需要管理,这可能会变得令人厌烦。在这种情况下,我们可以使用属性jdk.internal.httpclient.disableHostnameVerification来禁用主机名验证。

We can set this property when running the application as a command-line argument:

我们可以在运行应用程序时作为一个命令行参数设置这个属性。

java -Djdk.internal.httpclient.disableHostnameVerification=true -jar target/java-httpclient-ssl-0.0.1-SNAPSHOT.jar

Alternatively, we can programmatically set this property before creating our client:

另外,我们可以在创建我们的客户端之前以编程方式设置该属性

Properties props = System.getProperties();
props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString());

HttpClient httpClient = HttpClient.newHttpClient();

When we run the test now, we’ll see that it passes.

当我们现在运行这个测试时,我们会看到它通过了。

We should note that changing the property would mean that certificate verification is disabled for all requests. This may not be desirable, especially in production. However, it’s common to introduce this property in non-production environments.

我们应该注意,改变该属性将意味着对所有请求禁用证书验证。 这可能不可取,特别是在生产环境中。然而,在非生产环境中引入该属性是很常见的。

5. Can We Use Java HttpClient With Spring?

5.我们可以在Spring中使用Java HttpClient吗?

Spring provides two popular interfaces to make HTTP requests:

Spring提供了两个流行的接口来进行HTTP请求。

  • RestTemplate for synchronous requests
  • WebClient for synchronous and asynchronous requests

Both can be used along with popular HTTP clients such as Apache HttpClient, OkHttp, and the old HttpURLConnection. However, we can’t plug Java HttpClient into these two interfaces. It’s rather seen as an alternative to them.

两者都可以与流行的HTTP客户端一起使用,如Apache HttpClient、OkHttp和旧的HttpURLConnection。然而,我们不能将Java HttpClient插入这两个接口它反而被看作是它们的替代品。

We can use Java HttpClient to make synchronous and asynchronous requests, convert requests and responses, add timeouts, etc. Therefore, it can be utilized directly without needing Spring’s interfaces.

我们可以使用Java HttpClient来进行同步和异步请求,转换请求和响应,添加超时等等。因此,可以直接利用它而不需要Spring的接口。

6. Conclusion

6.结语

In this article, we explored how to use the Java HTTP Client to connect to a server that requires SSL. We also looked at ways to use the client with URLs that don’t have a valid certificate.

在这篇文章中,我们探讨了如何使用Java HTTP客户端连接到一个需要SSL的服务器。我们还研究了对没有有效证书的URL使用客户端的方法。

As always, the code for these examples is available over on GitHub.

像往常一样,这些例子的代码可以在GitHub上找到over