Affects: 6.0.5 (perhaps down to 5.0, the since value on BodyInserters)


Currently in BodyInserters, FormInserter only supports a blocking supply of values, and MultipartInserter extends that interface with support for values from a Publisher. Each interface's Default[...] implementation then provides the relevant MediaType when inserting the content. The async support is therefore coupled with using MediaType.MULTIPART_FORM_DATA.

It would be nice if the async support were available in FormInserter/DefaultFormInserter, such that a client could provide the form values reactively while still using MediaType.APPLICATION_FORM_URLENCODED / FORM_DATA_TYPE.

Comment From: poutsma

As it turns out, you can use the FormPartEvent API to accomplish what you want, and then use the resulting Flux<FormPartEvent> as body. I have added a tests that shows how to do this here: https://github.com/spring-projects/spring-framework/blob/faaf3a61f2944d80b8919c8900325db097944f24/spring-web/src/test/java/org/springframework/http/codec/multipart/PartEventHttpMessageWriterTests.java#L99

Comment From: nmck257

Thanks for that.

I wasn't actually able to accomplish my goal with FluxFormPartEvent. This sample:

WebClient.create().post().uri("http://localhost:%s".formatted(mockWebServer.getPort()))
        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
        .body(Flux.concat(Mono.just(FormPartEvent.create("key", "value"))), PartEvent.class)
        .retrieve()
        .toBodilessEntity()
        .block();

...yields an exception like this:

org.springframework.web.reactive.function.client.WebClientRequestException: Content type 'application/x-www-form-urlencoded' not supported for bodyType=org.springframework.http.codec.multipart.PartEvent

Looks like the default PartEventHttpMessageWriter is only configured for MediaType.MULTIPART_FORM_DATA.

But after trying that, I did have success with something more like:

WebClient.create().post().uri("http://localhost:%s".formatted(mockWebServer.getPort()))
        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
        .body(Mono.just(new LinkedMultiValueMap()), MultiValueMap.class)
        .retrieve()
        .toBodilessEntity()
        .block();

...reliant on MultipartHttpMessageWriter. Maybe there's value in updating the javadocs for BodyInserters::fromFormData to call out alternatives like this?

(tested using spring-framework 6.0.12)