Apache HttpClient vs. CloseableHttpClient – Apache HttpClient vs. CloseableHttpClient

最后修改: 2022年 4月 10日

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

1. Overview

1.概述

Apache HttpClient is a popular Java library providing efficient and feature-rich packages implementing the client-side of the most recent HTTP standards. The library is designed for extension while providing robust support for the base HTTP methods.

Apache HttpClient是一个流行的Java库,提供高效且功能丰富的包,实现了最新的HTTP标准的客户端。该库为扩展而设计,同时为基本的HTTP方法提供了强大的支持。

In this tutorial, we’ll look at the Apache HttpClient API design. We’ll explain the difference between HttpClient and CloseableHttpClient. In addition, we’ll check how to create CloseableHttpClient instances using HttpClients or HttpClientBuilder.

在本教程中,我们将看一下Apache HttpClient API的设计。我们将解释HttpClientCloseableHttpClient之间的区别。此外,我们将检查如何使用HttpClientsHttpClientBuilder创建CloseableHttpClient实例。

Finally, we’ll recommend which of the mentioned APIs we should be using in our custom code. Also, we’ll look at which API classes implement the Closeable interface, thus requiring us to close their instances in order to free up resources.

最后,我们将推荐我们应该在我们的自定义代码中使用哪些提到的API。此外,我们还将看看哪些API类实现了Closeable 接口,从而要求我们关闭它们的实例,以释放资源。

2. API Design

2.API设计

Let’s start by looking at how the API is designed, focusing on its high-level classes and interfaces. In the class diagram below, we’ll show a part of the API required for the classic execution of HTTP requests and processing HTTP responses:

让我们先来看看API是如何设计的,重点是它的高层类和接口。在下面的类图中,我们将展示经典的执行HTTP请求和处理HTTP响应所需的API的一部分。

Apache Classic HTTP Client

In addition, Apache HttpClient API also supports asynchronous HTTP request/response exchange, as well as reactive message exchange using RxJava.

此外,Apache HttpClient API还支持异步HTTP请求/响应交换,以及使用RxJava进行反应式消息交换。

3. HttpClient vs. CloseableHttpClient

3.HttpClientCloseableHttpClient

HttpClient is a high-level interface that represents the basic contract for HTTP request execution. It imposes no restrictions on the request execution process. Also, it leaves specifics like state management, authentication, and redirects to individual client implementations.

HttpClient是一个高级接口,代表了HTTP请求执行的基本契约。它对请求的执行过程没有任何限制。此外,它还将状态管理、认证和重定向等具体细节留给各个客户端实现。

We can cast any client implementation to the HttpClient interface. Thus, we may use it to execute basic HTTP requests via the default client implementation:

我们可以将任何客户端的实现投到HttpClient接口。因此,我们可以用它来通过默认的客户端实现执行基本的HTTP请求。

HttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(serviceUrl);
HttpResponse response = httpClient.execute(httpGet);
assertThat(response.getCode()).isEqualTo(HttpStatus.SC_OK);

However, the code above will result in a blocker issue on SonarQube. The reason is that the default client implementation returns an instance of CloseableHttpClient, which requires closing.

然而,上面的代码将导致阻断器问题SonarQube上出现。原因是默认的客户端实现会返回一个CloseableHttpClient的实例,这需要关闭。

CloseableHttpClient is an abstract class that represents a base implementation of the HttpClient interface. However, it also implements the Closeable interface. Thus, we should close all its instances after use. We can close them by using either try-with-resources or by calling the close method in a finally clause:

CloseableHttpClient是一个抽象类,代表了HttpClient接口的基础实现。然而,它也实现了Closeable接口。因此,我们应该在使用后关闭它的所有实例。我们可以通过使用try-with-resources或者通过在finally子句中调用close方法来关闭它们。

try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
    HttpGet httpGet = new HttpGet(serviceUrl);
    HttpResponse response = httpClient.execute(httpGet);
    assertThat(response.getCode()).isEqualTo(HttpStatus.SC_OK);
}

Therefore, in our custom code, we should use the CloseableHttpClient class, not the HttpClient interface.

因此,在我们的自定义代码中,我们应该使用CloseableHttpClient类,而不是HttpClient接口

4. HttpClients vs. HttpClientBuilder

4. HttpClientsHttpClientBuilder

In the above examples, we used a static method from the HttpClients class to obtain a default client implementation. HttpClients is a utility class containing factory methods for creating CloseableHttpClient instances:

在上面的例子中,我们使用了HttpClients类中的一个静态方法来获得一个默认的客户端实现。HttpClients是一个实用类,包含了用于创建CloseableHttpClient实例的工厂方法

CloseableHttpClient httpClient = HttpClients.createDefault();

We can achieve the same using the HttpClientBuilder class. HttpClientBuilder is an implementation of the Builder design pattern for creating CloseableHttpClient instances:

我们可以使用HttpClientBuilder实现同样的功能。HttpClientBuilderBuilder设计模式的一个实现,用于创建CloseableHttpClient实例

CloseableHttpClient httpClient = HttpClientBuilder.create().build();

Internally, HttpClients uses HttpClientBuilder to create client implementation instances. Therefore, we should prefer to use HttpClients in our custom code. Given that it is a higher-level class, its internals might change with new releases.

在内部,HttpClients使用HttpClientBuilder来创建客户端实现实例。因此,我们应该倾向于在我们的自定义代码中使用HttpClients。鉴于它是一个更高层次的类,它的内部结构可能会随着新版本的发布而改变。

5. Resource Management

5.资源管理

The reason why we need to close CloseableHttpClient instances once they go out of scope is to shut down the associated connection manager. In addition, we should also use CloseableHttpResponse in order to ensure proper deallocation of system resources.

一旦实例超出范围,我们需要关闭CloseableHttpClient实例的原因是为了关闭相关的连接管理器。此外,我们还应该使用CloseableHttpResponse,以确保系统资源的正确去分配

5.1. CloseableHttpResponse

5.1. 可关闭HttpResponse

CloseableHttpResponse is a class implementing the ClassicHttpResponse interface. However, ClassicHttpResponse also extends HttpResponse, HttpEntityContainer, and Closeable interfaces.

CloseableHttpResponse是一个实现ClassicHttpResponse接口的类。然而,ClassicHttpResponse还扩展了HttpResponseHttpEntityContainerCloseable接口。

The underlying HTTP connection is held by the response object to allow the response content to be streamed directly from the network socket. Therefore, we should use the CloseableHttpResponse class instead of the HttpResponse interface in our custom code. We also need to make sure to call the close method once we consume the response:

底层的HTTP连接由响应对象持有,以允许响应内容直接从网络套接字中流出来。因此,我们应该在自定义代码中使用CloseableHttpResponse类而不是HttpResponse接口。我们还需要确保,一旦我们消费了响应,就调用close方法。

try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
    HttpGet httpGet = new HttpGet(serviceUrl);
    try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
        HttpEntity entity = response.getEntity();
        EntityUtils.consume(entity);
    }
}

We should note that the underlying connection cannot be safely re-used when response content is not fully consumed. In such situations, the connection will be shut down and discarded by the connection manager.

我们应该注意,当响应内容没有被完全消耗时,底层连接不能被安全地重新使用。在这种情况下,连接将被关闭并被连接管理器丢弃。

5.2. Reusing Clients

5.2.重用客户端

Closing a CloseableHttpClient instance and creating a new one for every request could be an expensive operation. Instead, we can reuse a single instance of a CloseableHttpClient for sending multiple requests:

关闭一个CloseableHttpClient实例并为每个请求创建一个新的实例可能是一个昂贵的操作。相反,我们可以重用一个CloseableHttpClient的单一实例来发送多个请求

try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
    HttpGet httpGetOne = new HttpGet(serviceOneUrl);
    try (CloseableHttpResponse responseOne = httpClient.execute(httpGetOne)) {
        HttpEntity entityOne = responseOne.getEntity();
        EntityUtils.consume(entityOne);
        assertThat(responseOne.getCode()).isEqualTo(HttpStatus.SC_OK);
    }

    HttpGet httpGetTwo = new HttpGet(serviceTwoUrl);
    try (CloseableHttpResponse responseTwo = httpClient.execute(httpGetTwo)) {
        HttpEntity entityTwo = responseTwo.getEntity();
        EntityUtils.consume(entityTwo);
        assertThat(responseTwo.getCode()).isEqualTo(HttpStatus.SC_OK);
    }
}

As a result, we avoid shutting down the internally associated connection manager and creating a new one.

因此,我们避免关闭内部关联的连接管理器并创建一个新的。

6. Conclusion

6.结语

In this article, we explored the classic HTTP API of Apache HttpClient, a popular client-side HTTP library for Java.

在这篇文章中,我们探索了Apache HttpClient的经典HTTP API,这是一个流行的Java客户端HTTP库。

We learned the difference between HttpClient and CloseableHttpClient. Also, we recommended using CloseableHttpClient in our custom code. Next, we saw how to create CloseableHttpClient instances using HttpClients or HttpClientBuilder.

我们学习了HttpClientCloseableHttpClient之间的区别。另外,我们建议在我们的自定义代码中使用CloseableHttpClient。接下来,我们看到如何使用HttpClientsHttpClientBuilder创建CloseableHttpClient实例。

Finally, we looked at CloseableHttpClient and CloseableHttpResponse classes, both implementing the Closeable interface. We saw that their instances should be closed in order to free up resources.

最后,我们看了CloseableHttpClientCloseableHttpResponse都实现了Closeable接口。我们看到,它们的实例应该被关闭,以便释放资源。

As always, the complete source code is available over on GitHub.

一如既往,完整的源代码可在GitHub上获得