リクエストボディー

リクエスト本体は、次の例に示すように、Mono や Kotlin コルーチン Deferred など、ReactiveAdapterRegistry によって処理される任意の非同期型からエンコードできます。

  • 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>()

次の例に示すように、オブジェクトのストリームをエンコードすることもできます。

  • 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 ショートカットメソッドを使用できます。

  • 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>()

フォームデータ

フォームデータを送信するには、MultiValueMap<String, String> を本文として提供できます。コンテンツは FormHttpMessageWriter によって application/x-www-form-urlencoded に自動的に設定されることに注意してください。次の例は、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 を使用してインラインでフォームデータを提供することもできます。

  • 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>()

マルチパートデータ

マルチパートデータを送信するには、パーツのコンテンツを表す Object インスタンスまたはパーツのコンテンツとヘッダーを表す HttpEntity インスタンスのいずれかである MultiValueMap<String, ?> を提供する必要があります。MultipartBodyBuilder は、マルチパートリクエストを準備するための便利な API を提供します。次の例は、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 を明示的に提供できます。

MultiValueMap を準備したら、次の例に示すように、WebClient に渡す最も簡単な方法は body メソッドを使用することです。

  • 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 に少なくとも 1 つの String 以外の値(通常のフォームデータ(つまり application/x-www-form-urlencoded)を表す場合もある)が含まれている場合、Content-Type を multipart/form-data に設定する必要はありません。これは、MultipartBodyBuilder を使用する場合に常に当てはまり、HttpEntity ラッパーが保証されます。

MultipartBodyBuilder の代替として、次の例に示すように、組み込みの BodyInserters を介して、インラインスタイルのマルチパートコンテンツを提供することもできます。

  • 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 オブジェクトを介してマルチパートコンテンツを提供できます。

  • フォームフィールドは FormPartEvent::create で作成できます。

  • ファイルのアップロードは FilePartEvent::create 経由で作成できます。

Flux::concat を介してメソッドから返されたストリームを連結し、WebClient のリクエストを作成できます。

たとえば、このサンプルは、フォームフィールドとファイルを含むマルチパートフォームを POST します。

  • 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 経由で別のサービスに中継できます。