Reputation: 283
I went through similar tickets (i.e. How to stream file from Multipart/form-data in Spring WebFlux), but apparently I have slightly different case.
High-level example (no error handling / no 'empty' checks):
Controller:
@ResponseStatus(code = HttpStatus.CREATED)
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<String> create(
@RequestPart(value = "images", required = false) final Flux<FilePart> images
) {
...service-call...
}
Service:
public Mono<String> create(
final Flux<FilePart> images
) {
MultipartBodyBuilder builder = new MultipartBodyBuilder();
return images
.filter(part -> Objects.nonNull(part.headers().getContentType()))
.filter(part ->
part.headers().getContentType().includes(MediaType.IMAGE_JPEG)
|| part.headers().getContentType().includes(MediaType.IMAGE_PNG)
)
.doOnNext(
part -> builder
.asyncPart("images", part.content(), DataBuffer.class)
.filename(part.filename())
)
.then(webClient.post()
.uri(URI_RESOURCE)
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve()
.bodyToMono(String.class)
);
}
the problem is, client does not receive actual "images" :( I added some doOnNext
to log the fact that files are added to builder, so I know they are.
I assume it is because of .asyncPart("images", part.content(), DataBuffer.class)
but not sure how to avoid / bypass this internal publisher?
As a note, controller expects a Flux
based on all recommendations I saw; however switching to plain List<FilePart>
, solves the problem, while I think it is an anti-pattern to assume "blocking" request in WebFlux, right?
Upvotes: 2
Views: 2030
Reputation: 241
The problem is your then(webClient...)
block is already called and MultipartBodyBuilder.build() is executed at the start of the request. You can wrap then
part with Mono.defer
.
...
.then(Mono.defer(() -> {
return webClient.post()
.uri(URI_RESOURCE)
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve()
.bodyToMono(String.class);
}));
Upvotes: 2