Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported for @RequestBody MultiValueMap
Asked Answered
L

12

169

Based on the answer for problem with x-www-form-urlencoded with Spring @Controller

I have written the below @Controller method

@RequestMapping(value = "/{email}/authenticate", method = RequestMethod.POST
            , produces = {"application/json", "application/xml"}
            ,  consumes = {"application/x-www-form-urlencoded"}
    )
     public
        @ResponseBody
        Representation authenticate(@PathVariable("email") String anEmailAddress,
                                    @RequestBody MultiValueMap paramMap)
                throws Exception {


            if(paramMap == null || paramMap.get("password") == null) {
                throw new IllegalArgumentException("Password not provided");
            }
    }

the request to which fails with the below error

{
  "timestamp": 1447911866786,
  "status": 415,
  "error": "Unsupported Media Type",
  "exception": "org.springframework.web.HttpMediaTypeNotSupportedException",
  "message": "Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported",
  "path": "/users/usermail%40gmail.com/authenticate"
}

[PS: Jersey was far more friendly, but couldn't use it now given the practical restrictions here]

Loophole answered 19/11, 2015 at 5:51 Comment(5)
Did you add consumes = {"application/x-www-form-urlencoded"} in @RequestBody?Tound
How did you execute the request? add the code of (js,jquery, curl or whatever you use ) .Cresa
I have the same problem. In my case I use jquery ajax to post the data and the data is JSON.stringify({"ordersToDownload":"00417002"}Nardi
This is the code I use: $.ajax({url:"/myurl", type:"POST", data: JSON.stringify({"someAttribute":"someData"}) })Nardi
Check my answer out enter link description hereQuitclaim
A
215

The problem is that when we use application/x-www-form-urlencoded, Spring doesn't understand it as a RequestBody. So, if we want to use this we must remove the @RequestBody annotation.

Then try the following:

@RequestMapping(
  path = "/{email}/authenticate", 
  method = RequestMethod.POST,
  consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, 
  produces = {
    MediaType.APPLICATION_ATOM_XML_VALUE, 
    MediaType.APPLICATION_JSON_VALUE
  })
public @ResponseBody Representation authenticate(
  @PathVariable("email") String anEmailAddress, 
  MultiValueMap paramMap) throws Exception {

  if (paramMap == null && 
      paramMap.get("password") == null) {
     throw new IllegalArgumentException("Password not provided");
  }
  return null;
}

Note that removed the annotation @RequestBody

answer: Http Post request with content type application/x-www-form-urlencoded not working in Spring

Akkad answered 7/7, 2016 at 18:37 Comment(7)
Thank you! Solves the problem. Now I wonder how do we explicitly remove the application/x-www-form-urlencoded ?Biotechnology
it is not necessary @kholofeloMalomaAkkad
If anyone wondered why this works without any annotation, it seems Spring handles any non annotated arguments as if they have @ModelAttribute, even though this behaviour is (sadly) not documented. And @ModelAttribute does understand x-www-form-urlencodedSwitzer
public ResponseEntity<?> getToken(MultiValueMap paramMap) IllegalArgumentException: argument type mismatchDeclinature
Thanks for the info! As a newbie, I am wondering what's the reason behind this little odd behaviour for Spring to parse the payload and bind it to object?Monocyclic
I believe that should be OR as opposed to AND (if paraMap is null the get will produce NPE ` if(paramMap == null || paramMap.get("password") == null) { throw new IllegalArgumentException("Password not provided"); } `Wreckful
Gives me an error No primary or single unique constructor found for interface org.apache.commons.collections4.MultiValuedMapGalcha
W
102

It seems that now you can just mark the method parameter with @RequestParam and it will do the job for you.

@PostMapping( "some/request/path" )
public void someControllerMethod( @RequestParam Map<String, String> body ) {
  //work with Map
}
Womanizer answered 28/3, 2017 at 9:7 Comment(1)
this is valid on Spring Boot 2.4.2Mccubbin
G
23

Add a header to your request to set content type to application/json

curl -H 'Content-Type: application/json' -s -XPOST http://your.domain.com/ -d YOUR_JSON_BODY

this way spring knows how to parse the content.

Gaultiero answered 11/7, 2016 at 15:16 Comment(2)
You might need to also add an Accept header to your command: 'curl -vk -H "Accept: application/json" -H "Content-Type: application/json" ' etc.Cence
can you please explain how to add this setting to my HTML form ?Farouche
S
19

In Spring 5

@PostMapping( "some/request/path" )
public void someControllerMethod( @RequestParam MultiValueMap body ) {

    // import org.springframework.util.MultiValueMap;

    String datax = (String) body .getFirst("datax");
}
Smashandgrab answered 25/3, 2019 at 13:11 Comment(1)
Yeah, with inclusion of consumer=MediaType.APPLICATION_FORM_URLENCODED_VALUE in mapping, you deserve more points sir! thank you! @RequestParam seams to be required now for picking up MultiValueMap from the requestDelphinium
H
16

@RequestBody MultiValueMap paramMap

in here Remove the @RequestBody Annotaion

@RequestMapping(value = "/signin",method = RequestMethod.POST)
public String createAccount(@RequestBody LogingData user){
    logingService.save(user);
    return "login";
}

@RequestMapping(value = "/signin",method = RequestMethod.POST)
public String createAccount( LogingData user){
    logingService.save(user);
    return "login";
} 

like that

Hilel answered 24/12, 2020 at 15:2 Comment(1)
While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.Misfeasance
C
8

Simply removing @RequestBody annotation solves the problem (tested on Spring Boot 2):

@RestController
public class MyController {

    @PostMapping
    public void method(@Valid RequestDto dto) {
       // method body ...
    }
}
Cobra answered 10/10, 2019 at 7:38 Comment(0)
B
5
@PostMapping(path = "/my/endpoint", consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE })
public ResponseEntity<Void> handleBrowserSubmissions(MyDTO dto) throws Exception {
    ...
}

That way works for me

Bathtub answered 24/9, 2020 at 18:41 Comment(1)
This is the simplest answer; works for me on Spring Boot 2.6.0 on a @RestController.Aliquant
A
5

I met the same problem when I want to process my simple HTML form submission (without using thymeleaf or Spring's form tag) in Spring MVC.

The answer of Douglas Ribeiro will work very well. But just in case, for anyone, like me, who really want to use "@RequestBody" in Spring MVC.

Here is the cause of the problem:

  • Spring need to ① recognize the "Content-Type", and ② convert the content to the parameter type we declared in the method's signature.
  • The 'application/x-www-form-urlencoded' is not supported, because, by default, the Spring cannot find a proper HttpMessageConverter to do the converting job, which is step ②.

Solution:

  • We manually add a proper HttpMessageConverter into the Spring's configuration of our application.

Steps:

  1. Choose the HttpMessageConverter's class we want to use. For 'application/x-www-form-urlencoded', we can choose "org.springframework.http.converter.FormHttpMessageConverter".
  2. Add the FormHttpMessageConverter object to Spring's configuration, by calling the "public void configureMessageConverters(List<HttpMessageConverter<?>> converters)" method of the "WebMvcConfigurer" implementation class in our application. Inside the method, we can add any HttpMessageConverter object as needed, by using "converters.add()".

By the way, the reason why we can access the value by using "@RequestParam" is:

According to Servlet Specification (Section 3.1.1):

The following are the conditions that must be met before post form data will be populated to the parameter set: The request is an HTTP or HTTPS request. 2. The HTTP method is POST. 3. The content type is application/x-www-form-urlencoded. 4. The servlet has made an initial call of any of the getParameter family of methods on the request object.

So, the value in request body will be populated to parameters. But in Spring, you can still access RequestBody, even you can use @RequstBody and @RequestParam at the same method's signature. Like:

@RequestMapping(method = RequestMethod.POST, consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public String processForm(@RequestParam Map<String, String> inputValue,  @RequestBody MultiValueMap<String, List<String>> formInfo) {
    ......
    ......
}

The inputValue and formInfo contains the same data, excpet for the type for "@RequestParam" is Map, while for "@RequestBody" is MultiValueMap.

Achaemenid answered 28/11, 2021 at 23:22 Comment(0)
S
2

I wrote about an alternative in this StackOverflow answer.

There I wrote step by step, explaining with code. The short way:

First: write an object

Second: create a converter to mapping the model extending the AbstractHttpMessageConverter

Third: tell to spring use this converter implementing a WebMvcConfigurer.class overriding the configureMessageConverters method

Fourth and final: using this implementation setting in the mapping inside your controller the consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE and @RequestBody in front of your object.

I'm using spring boot 2.

Streamway answered 3/7, 2018 at 18:20 Comment(0)
J
0

You can try to turn support on in spring's converter

@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // add converter suport Content-Type: 'application/x-www-form-urlencoded'
        converters.stream()
                .filter(AllEncompassingFormHttpMessageConverter.class::isInstance)
                .map(AllEncompassingFormHttpMessageConverter.class::cast)
                .findFirst()
                .ifPresent(converter -> converter.addSupportedMediaTypes(MediaType.APPLICATION_FORM_URLENCODED_VALUE));
    }

}

Judicious answered 23/11, 2020 at 13:4 Comment(0)
M
0

Just add an HTTP Header Manager if you are testing using JMeter : enter image description here

Matrass answered 9/7, 2021 at 18:35 Comment(0)
H
-1

I found simple way. Just add @FormProperty annotation for each field of your request domain. Of course, you should use consumes = APPLICATION_FORM_URLENCODED_VALUE in your controller or client. Example:

public class AccessTokenRequest {

    @FormProperty("client_id")
    private String clientId;

    @FormProperty("username")
    private String username;

    @FormProperty("grant_type")
    private String grantType;
}
Hegarty answered 7/5, 2023 at 13:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.