跳到主要内容

请求体

ChatGPT-4o 中英对照 Request Body

请求体可以从 ReactiveAdapterRegistry 处理的任何异步类型进行编码,例如 Mono 或 Kotlin 协程的 Deferred,如下例所示:

Mono<Person> personMono = ... ;

Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(personMono, Person.class)
.retrieve()
.bodyToMono(Void.class);
java

您还可以对对象流进行编码,如以下示例所示:

Flux<Person> personFlux = ... ;

Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_STREAM_JSON)
.body(personFlux, Person.class)
.retrieve()
.bodyToMono(Void.class);
java

或者,如果你有实际值,你可以使用 bodyValue 快捷方法,如下例所示:

Person person = ... ;

Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(person)
.retrieve()
.bodyToMono(Void.class);
java

表单数据

要发送表单数据,你可以提供一个 MultiValueMap<String, String> 作为主体。注意,内容会被 FormHttpMessageWriter 自动设置为 application/x-www-form-urlencoded。下面的示例展示了如何使用 MultiValueMap<String, String>

MultiValueMap<String, String> formData = ... ;

Mono<Void> result = client.post()
.uri("/path", id)
.bodyValue(formData)
.retrieve()
.bodyToMono(Void.class);
java

您还可以通过使用 BodyInserters 内联提供表单数据,如以下示例所示:

import static org.springframework.web.reactive.function.BodyInserters.*;

Mono<Void> result = client.post()
.uri("/path", id)
.body(fromFormData("k1", "v1").with("k2", "v2"))
.retrieve()
.bodyToMono(Void.class);
java

多部分数据

要发送多部分数据,您需要提供一个 MultiValueMap<String, ?>,其值可以是表示部分内容的 Object 实例或表示部分内容和头信息的 HttpEntity 实例。MultipartBodyBuilder 提供了一个方便的 API 来准备一个多部分请求。以下示例展示了如何创建一个 MultiValueMap<String, ?>

MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("fieldPart", "fieldValue");
builder.part("filePart1", new FileSystemResource("...logo.png"));
builder.part("jsonPart", new Person("Jason"));
builder.part("myPart", part); // Part from a server request

MultiValueMap<String, HttpEntity<?>> parts = builder.build();
java

在大多数情况下,您不需要为每个部分指定 Content-Type。内容类型是根据选择的 HttpMessageWriter 自动确定的,或者在 Resource 的情况下,根据文件扩展名确定。如果有必要,您可以通过重载的构建器 part 方法之一显式提供用于每个部分的 MediaType

一旦准备好 MultiValueMap,将其传递给 WebClient 最简单的方法是通过 body 方法,如以下示例所示:

MultipartBodyBuilder builder = ...;

Mono<Void> result = client.post()
.uri("/path", id)
.body(builder.build())
.retrieve()
.bodyToMono(Void.class);
java

如果 MultiValueMap 包含至少一个非 String 值,这也可能代表常规表单数据(即 application/x-www-form-urlencoded),则无需将 Content-Type 设置为 multipart/form-data。使用 MultipartBodyBuilder 时总是这种情况,它确保了一个 HttpEntity 包装器。

作为 MultipartBodyBuilder 的替代方案,您还可以通过内置的 BodyInserters 以内联样式提供多部分内容,如以下示例所示:

import static org.springframework.web.reactive.function.BodyInserters.*;

Mono<Void> result = client.post()
.uri("/path", id)
.body(fromMultipartData("fieldPart", "value").with("filePart", resource))
.retrieve()
.bodyToMono(Void.class);
java

PartEvent

要顺序地流式传输多部分数据,可以通过 PartEvent 对象提供多部分内容。

  • 表单字段可以通过 FormPartEvent::create 创建。

  • 文件上传可以通过 FilePartEvent::create 创建。

你可以通过 Flux::concat 连接从方法返回的流,并为 WebClient 创建一个请求。

例如,此示例将 POST 一个包含表单字段和文件的多部分表单。

Resource resource = ...
Mono<String> result = webClient
.post()
.uri("https://example.com")
.body(Flux.concat(
FormPartEvent.create("field", "field value"),
FilePartEvent.create("file", resource)
), PartEvent.class)
.retrieve()
.bodyToMono(String.class);
java

在服务器端,通过 @RequestBodyServerRequest::bodyToFlux(PartEvent.class) 接收到的 PartEvent 对象可以通过 WebClient 转发到另一个服务。