Request Body
可以从 ReactiveAdapterRegistry
处理的任何异步类型对请求正文进行编码,如同以下示例所示:
The request body can be encoded from any asynchronous type handled by ReactiveAdapterRegistry
,
like Mono
or Kotlin Coroutines Deferred
as the following example shows:
-
Java
-
Kotlin
Mono<Person> personMono = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(personMono, Person.class)
.retrieve()
.bodyToMono(Void.class);
val personDeferred: Deferred<Person> = ...
client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body<Person>(personDeferred)
.retrieve()
.awaitBody<Unit>()
如以下示例所示,您也可以对对象的流进行编码:
You can also have a stream of objects be encoded, as the following example shows:
-
Java
-
Kotlin
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);
val people: Flow<Person> = ...
client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(people)
.retrieve()
.awaitBody<Unit>()
或者,如果您有实际值,可以使用 bodyValue
快捷方法,如同以下示例所示:
Alternatively, if you have the actual value, you can use the bodyValue
shortcut method,
as the following example shows:
-
Java
-
Kotlin
Person person = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(person)
.retrieve()
.bodyToMono(Void.class);
val person: Person = ...
client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(person)
.retrieve()
.awaitBody<Unit>()
Form Data
要发送表单数据,可以提供 MultiValueMap<String, String>
作为正文。请注意,内容由 FormHttpMessageWriter
自动设置为 application/x-www-form-urlencoded
。以下示例展示如何使用 MultiValueMap<String, String>
:
To send form data, you can provide a MultiValueMap<String, String>
as the body. Note that the
content is automatically set to application/x-www-form-urlencoded
by the
FormHttpMessageWriter
. The following example shows how to use MultiValueMap<String, String>
:
-
Java
-
Kotlin
MultiValueMap<String, String> formData = ... ;
Mono<Void> result = client.post()
.uri("/path", id)
.bodyValue(formData)
.retrieve()
.bodyToMono(Void.class);
val formData: MultiValueMap<String, String> = ...
client.post()
.uri("/path", id)
.bodyValue(formData)
.retrieve()
.awaitBody<Unit>()
如以下示例所示,您还可以使用 BodyInserters
内联提供表单数据:
You can also supply form data in-line by using BodyInserters
, as the following example shows:
-
Java
-
Kotlin
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);
import org.springframework.web.reactive.function.BodyInserters.*
client.post()
.uri("/path", id)
.body(fromFormData("k1", "v1").with("k2", "v2"))
.retrieve()
.awaitBody<Unit>()
Multipart Data
要发送多部分数据,您需要提供一个 MultiValueMap<String, ?>
,其值为表示部件内容的 Object
实例,或表示部件的内容和头的 HttpEntity
实例。MultipartBodyBuilder
提供了一个便捷的 API 来准备一个多部分请求。以下示例展示如何创建一个 MultiValueMap<String, ?>
:
To send multipart data, you need to provide a MultiValueMap<String, ?>
whose values are
either Object
instances that represent part content or HttpEntity
instances that represent the content and
headers for a part. MultipartBodyBuilder
provides a convenient API to prepare a
multipart request. The following example shows how to create a MultiValueMap<String, ?>
:
-
Java
-
Kotlin
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();
val builder = MultipartBodyBuilder().apply {
part("fieldPart", "fieldValue")
part("filePart1", FileSystemResource("...logo.png"))
part("jsonPart", Person("Jason"))
part("myPart", part) // Part from a server request
}
val parts = builder.build()
在大多数情况下,您不必为每个部件指定 Content-Type
。内容类型会根据选择的 HttpMessageWriter
自动确定,序列化或在 Resource
的情况下,基于文件扩展名自动确定。如果需要,您可以通过一个重载的构建器 part
方法为每个部件明确提供要使用的 MediaType
。
In most cases, you do not have to specify the Content-Type
for each part. The content
type is determined automatically based on the HttpMessageWriter
chosen to serialize it
or, in the case of a Resource
, based on the file extension. If necessary, you can
explicitly provide the MediaType
to use for each part through one of the overloaded
builder part
methods.
准备 MultiValueMap
后,最简单的传递给 WebClient
的方式是通过 body
方法,如同以下示例所示:
Once a MultiValueMap
is prepared, the easiest way to pass it to the WebClient
is
through the body
method, as the following example shows:
-
Java
-
Kotlin
MultipartBodyBuilder builder = ...;
Mono<Void> result = client.post()
.uri("/path", id)
.body(builder.build())
.retrieve()
.bodyToMono(Void.class);
val builder: MultipartBodyBuilder = ...
client.post()
.uri("/path", id)
.body(builder.build())
.retrieve()
.awaitBody<Unit>()
如果 MultiValueMap
包含至少一个非 String
值(可能也表示常规表单数据(即 application/x-www-form-urlencoded
)),则无需将 Content-Type
设置为 multipart/form-data
。使用 MultipartBodyBuilder
时总是如此,它确保一个 HttpEntity
包装器。
If the MultiValueMap
contains at least one non-String
value, which could also
represent regular form data (that is, application/x-www-form-urlencoded
), you need not
set the Content-Type
to multipart/form-data
. This is always the case when using
MultipartBodyBuilder
, which ensures an HttpEntity
wrapper.
与 MultipartBodyBuilder
作为替代方案,您也可以通过内置 BodyInserters
以内联样式提供多部分内容,如同以下示例所示:
As an alternative to MultipartBodyBuilder
, you can also provide multipart content,
inline-style, through the built-in BodyInserters
, as the following example shows:
-
Java
-
Kotlin
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);
import org.springframework.web.reactive.function.BodyInserters.*
client.post()
.uri("/path", id)
.body(fromMultipartData("fieldPart", "value").with("filePart", resource))
.retrieve()
.awaitBody<Unit>()
PartEvent
要顺序流式传输多部分数据,您可以通过 PartEvent
对象提供多部分内容。
To stream multipart data sequentially, you can provide multipart content through PartEvent
objects.
-
Form fields can be created via
FormPartEvent::create
. -
File uploads can be created via
FilePartEvent::create
.
您可以通过 Flux::concat
连接方法返回的流,并为 WebClient
创建一个请求。
You can concatenate the streams returned from methods via Flux::concat
, and create a request for
the WebClient
.
例如,此示例将发布包含一个表单字段和一个文件的 multipart 表单。
For instance, this sample will POST a multipart form containing a form field and a file.
-
Java
-
Kotlin
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);
var resource: Resource = ...
var result: Mono<String> = webClient
.post()
.uri("https://example.com")
.body(
Flux.concat(
FormPartEvent.create("field", "field value"),
FilePartEvent.create("file", resource)
)
)
.retrieve()
.bodyToMono()
在服务器端,通过 @RequestBody
或 ServerRequest::bodyToFlux(PartEvent.class)
收到的 PartEvent
对象可以通过 WebClient
中继到另一个服务。
On the server side, PartEvent
objects that are received via @RequestBody
or
ServerRequest::bodyToFlux(PartEvent.class)
can be relayed to another service
via the WebClient
.