Content type 'application/x-www-form-urlencoded' not working with @RequestBody for WebFlux application

6.4k views Asked by At

Based on multiple thread regarding topic "'application/x-www-form-urlencoded' not working with @RequestBody" I haven't been successful in finding a solution for WebFlux Spring application.

I have a WebFlux Controller method:

    @PostMapping(value = "/endpoint", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
        public Mono<AddRecipientResponse> createRecipient(@RequestBody
                                                  final MultiValueMap<String, String> formData,
                                                  @RequestHeader
                                                  final Map<String, String> headers) {

But when I post my reqest I'm getting this error:

Could not resolve parameter [0] ... RecipientController.createRecipient(long,org.springframework.util.MultiValueMap<java.lang.String, java.lang.String>,java.util.Map<java.lang.String, java.lang.String>): 415 UNSUPPORTED_MEDIA_TYPE

Most of the solution rely on replacing @RequestBody with @RequestParam. However this cannot apply for my case. I need to have both @RequestBody and consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE. I tried following steps described in following threads, but off of them are for Spring MVC.

https://stackoverflow.com/a/70148328/18734587

https://stackoverflow.com/a/51160620/18734587

Have anyone figured out how to solve 415 UNSUPPORTED_MEDIA_TYPE error for a request with MediaType.APPLICATION_FORM_URLENCODED and @RequestBody for a WebFlux application?

3

There are 3 answers

0
SourceVisor On

Quoting this answer here

Spring doesn't recognize it's a RequestBody when using application/x-www-form-urlencoded.

Try to remove @RequestBody annotation.

I find it to be absolutely spot-on.

0
limak111 On

I came up with a solution on my own. Request body is extracted from ServerWebExchange.getFormData(), like this:

@PostMapping(value = "/endpoint", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public Mono<AddRecipientResponse> createRecipient(@RequestHeader final Map<String, String> headers,
                                                      ServerWebExchange serverWebExchange) {

        return serverWebExchange.getFormData()
                .flatMap(formData -> recipientService.createRecipient(headers, formData));
    }
0
Jose Antonio Jimenez Saez On

I have been struggling with this a morning. From the documented annotation @RequestParam

Supported for annotated handler methods in Spring MVC and Spring WebFlux as follows:

In Spring MVC, "request parameters" map to query parameters, form data, and parts in multipart requests. This is because the Servlet API combines query parameters and form data into a single map called "parameters", and that includes automatic parsing of the request body.

In Spring WebFlux, "request parameters" map to query parameters only. To work with all 3, query, form data, and multipart data, you can use data binding to a command object annotated with ModelAttribute.

Then after trying with @ModelAttribute from the documentation of Spring WebFlux only way to come to implement this in the documentation was:

https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-form-data

Java with annotated controller:

@PostMapping(value = "/endpoint", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String createRecipient(ServerWebExchange serverWebExchange) {

    MultiValueMap<String, String> formData = serverWebExchange.getFormData().block();
    return formData.toString();
}

Kotlin with annotated controller and coroutines:

@PostMapping(value = ["/endpoint"], consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
suspend fun createRecipient(serverWebExchange: ServerWebExchange): String? {
    val formData: MultiValueMap<String, String> = serverWebExchange.formData.awaitSingle()
    return formData.toString()
}