[WebClient] RequestBody
RequestBody는 다음 예제와 같이 Mono나 Kotlin의 Deferred와 같이 ReactiveAdapterRegistry에서 처리되는 비동기 형식에서 인코딩될 수 있습니다.
Mono<Person> personMono = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(personMono, Person.class)
.retrieve()
.bodyToMono(Void.class);
아래 예제와 같이 객체의 스트림을 인코딩할 수도 있습니다.
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);
또는 실제 값이 있는 경우, bodyValue 단축 메서드를 사용할 수 있습니다.
Person person = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(person)
.retrieve()
.bodyToMono(Void.class);
Form Data
Form Data 를 보내려면 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);
또한 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);
Multipart Data
Multipart Data 를 보내려면 값을 나타내는 개체 또는 부분 콘텐츠를 나타내는 HttpEntity 인스턴스 중 하나로 구성된 MultiValueMap<String, ?>를 제공해야 합니다. 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); // 서버 요청에서 받은 부분
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
대부분의 경우, 각 부분에 대해 Content-Type을 명시할 필요가 없습니다. 콘텐츠 유형은 해당 부분을 직렬화하기 위해 선택된 HttpMessageWriter에 따라 자동으로 결정됩니다. 또는 Resource의 경우 파일 확장자에 따라 결정됩니다. 필요한 경우, 오버로드된 빌더 부분 메서드 중 하나를 통해 각 부분에 대한 사용할 MediaType를 명시적으로 제공할 수 있습니다.
준비된 MultiValueMap이 있다면, WebClient에 전달하는 가장 쉬운 방법은 다음 예제와 같이 body 메서드를 통해 전달하는 것입니다:
MultipartBodyBuilder builder = ...;
Mono<Void> result = client.post()
.uri("/path", id)
.body(builder.build())
.retrieve()
.bodyToMono(Void.class);
MultiValueMap에 적어도 하나의 문자열이 아닌 값이 포함되어 있으면, 이 값은 일반적인 폼 데이터(application/x-www-form-urlencoded)를 나타낼 수 있으며, 따라서 Content-Type을 multipart/form-data로 설정할 필요가 없습니다. 이것은 항상 MultipartBodyBuilder를 사용할 때의 경우입니다.
MultipartBodyBuilder 대신에 BodyInserters를 사용하여 내장된 멀티파트 콘텐츠를 인라인으로 제공할 수도 있습니다.
MultipartBodyBuilder builder = ...;
Mono<Void> result = client.post()
.uri("/path", id)
.body(builder.build())
.retrieve()
.bodyToMono(Void.class);
1. 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);
서버 측에서 @RequestBody나 ServerRequest::bodyToFlux(PartEvent.class)를 통해 받은 PartEvent 개체는 다른 서비스를 통해 WebClient를 통해 전달할 수 있습니다.