Java 11 中新的 HttpClient API概览

概述

Java 11 中引入了新的 HttpClient API。它替代了不适合 HTTP 协议的旧 HttpURLConnection API。这个新的 API 使用构建器模式和流畅的 API 来创建所需的对象以通过网络进行通信。它还提供以下功能:

  1. 支持HTTP2协议。
  2. SSL 加密。
  3. 同步和异步通信模型。
  4. 支持 HTTP 方法。
  5. 身份验证机制(基本)。
  6. 饼干。

API 包含三个主要类:

  • HttClient 用于发送多个请求并通过网络接收响应。
  • HttpRequest 是一个不可变的类,表示要发送的 http 请求。可以为特定的 HTTP 方法配置它并附加正文(如果有)。
  • HttpResponse 描述来自 Web 服务器的响应。它在提交请求时由 HttpClient 返回。如果调用是异步的,它返回一个 CompletableFuture。

步骤很简单。首先,创建一个 HttpClient 实例,然后发送 HTTP 请求。最后,将请求传递给 HttpClient 发送方法并返回响应对象(如果调用是异步的,则返回 CompletableFuture)。

实际用例

事不宜迟,让我们看一些例子:

对于此演示,SpringBoot REST 应用程序将公开一个 允许列出/添加/更新/删除客户的端点(位于http://localhost:8080/api/v1/customers) 。 Customer 只是一个具有几个成员的不可变 POJO 类。在 HttpClient API 的帮助下,我们将在与服务交互时执行 CRUD 操作。

1.获取客户列表

第一个场景是获取所有客户的列表。这只是对客户资源 URL 的 GET 请求。

代码语言:javascript
复制
HttpClient client = HttpClient
    .newBuilder()
    .connectTimeout(Duration.ofMillis(500))
    .build();

请注意,如果半秒内未建立连接,连接将超时。接下来是 http 请求对象。

代码语言:javascript
复制
HttpRequests request = HttpRequest
    .newBuilder()
    .uri(URI.create("http://localhost:8080/api/v1/customers"))
    .header("Content-Type", "application/json")
    .GET()
    .build();

现在可以同步进行通信,即在收到响应之前阻塞执行。

代码语言:javascript
复制
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
System.out.printf("Response %s \n", response.body());

BodyHandlers 类包含将响应主体数据转换为 Java 对象(如 String)的便捷方法。

程序输出

代码语言:javascript
复制
Status 200 
Response [
{"id":1,"name":"Joe Smith","email":"joe.smith@gmail.com","dateOfBirth":"2008-01-01"},
{"id":2,"name":"Robert Moody","email":"robert.moody@gmail.com","dateOfBirth":"1985-06-21"},
{"id":3,"name":"Jennifer Dolan","email":"jennifer.dolan@gmail.com","dateOfBirth":"1966-11-11"},
{"id":4,"name":"Christopher Farrel","email":"christopher.farrel@gmail.com","dateOfBirth":"1970-04-15"},
{"id":5,"name":"Caroline Red","email":"caroline.red@gmail.com","dateOfBirth":"1992-03-05"}
] 

我们可以调用 sendAsynch 方法异步发送相同的请求。这个调用是非阻塞的,它会 立即返回一个 CompletableFuture。

代码语言:javascript
复制
CompletableFuture<HttpResponse<String>> responseFuture = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

responseFuture
.thenApply(HttpResponse::body)
.thenApply(String::toUpperCase)
.thenAccept(System.out::println)
.join();

在上面的管道中,主体是从响应中提取的,大写并打印。

程序输出

代码语言:javascript
复制
[
{"ID":1,"NAME":"JOE SMITH","EMAIL":"JOE.SMITH@GMAIL.COM","DATEOFBIRTH":"2008-01-01"},
{"ID":2,"NAME":"ROBERT MOODY","EMAIL":"ROBERT.MOODY@GMAIL.COM","DATEOFBIRTH":"1985-06-21"},
{"ID":3,"NAME":"JENNIFER DOLAN","EMAIL":"JENNIFER.DOLAN@GMAIL.COM","DATEOFBIRTH":"1966-11-11"},
{"ID":4,"NAME":"CHRISTOPHER FARREL","EMAIL":"CHRISTOPHER.FARREL@GMAIL.COM","DATEOFBIRTH":"1970-04-15"},
{"ID":5,"NAME":"CAROLINE RED","EMAIL":"CAROLINE.RED@GMAIL.COM","DATEOFBIRTH":"1992-03-05"}
]

2.创建新客户

POST 方法将用于创建新客户。主体必须填充 JSON 格式的客户数据。BodyPublishers 类提供方便的方法将 java 对象转换为数据流,以便作为请求主体发送。

代码语言:javascript
复制
HttpRequest request = HttpRequest
.newBuilder()
.uri(URI.create("http://localhost:8080/api/v1/customers"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{"name":"Sonia Lamar","email":"sonia.lamar@mail.com","dateOfBirth":"1998-07-29"}"))
.build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
System.out.printf("Location %s \n", response.headers().map().get("location"));

程序输出

代码语言:javascript
复制
Status 201
Location [http://localhost:8080/api/v1/customers/6]

3.更新一个新客户

PUT 方法将用于完全替换现有客户。这意味着除了 id 之外的所有字段都将被更改。对于部分更新,例如仅更新电子邮件,PATCH 方法更合适。

代码语言:javascript
复制
HttpRequest request = HttpRequest
.newBuilder()
.uri(URI.create("http://localhost:8080/api/v1/customers/4"))
.header("Content-Type", "application/json")
.PUT(HttpRequest.BodyPublishers.ofString("{"name":"Victor Martin","email":"victor.martin@mail.com","dateOfBirth":"1977-04-15"}"))
.build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
System.out.printf("Body %s \n", response.body());

程序输出

代码语言:javascript
复制
Status 200
Body {"id":4,"name":"Victor Martin","email":"victor.martin@mail.com","dateOfBirth":"1977-04-15"}

4.删除新客户

最后一个场景是删除 id 为 3 的客户。

代码语言:javascript
复制
var request = HttpRequest
.newBuilder()
.uri(URI.create("http://localhost:8080/api/v1/customers/3"))
.header("Content-Type", "application/json")
.DELETE()
.build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());

程序输出

代码语言:javascript
复制
Status 204