概述
Java 11 中引入了新的 HttpClient API。它替代了不适合 HTTP 协议的旧 HttpURLConnection API。这个新的 API 使用构建器模式和流畅的 API 来创建所需的对象以通过网络进行通信。它还提供以下功能:
- 支持HTTP2协议。
- SSL 加密。
- 同步和异步通信模型。
- 支持 HTTP 方法。
- 身份验证机制(基本)。
- 饼干。
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