O tipo de conteúdo 'application / x-www-form-urlencoded; charset = UTF-8' não é compatível com @RequestBody MultiValueMap

100

Com base na resposta para o problema com x-www-form-urlencoded com Spring @Controller

Eu escrevi o método @Controller abaixo

@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");
            }
    }

a solicitação que falha com o erro abaixo

{
  "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 era muito mais amigável, mas não poderia usá-la agora devido às restrições práticas aqui]

Somasundaram Sekar
fonte
Você adicionou consumes = {"application / x-www-form-urlencoded"} em @RequestBody?
shiladitya de
1
Como você executou a solicitação? adicione o código de (js, jquery, curl ou o que quer que você use).
Nikolay Rusev
Eu tenho o mesmo problema. No meu caso, eu uso jquery ajax para postar os dados e os dados sãoJSON.stringify({"ordersToDownload":"00417002"}
Arashsoft
Este é o código que uso:$.ajax({url:"/myurl", type:"POST", data: JSON.stringify({"someAttribute":"someData"}) })
Arashsoft
Verifique minha resposta e insira a descrição do link aqui
Eshiett Oto-obong

Respostas:

130

O problema é que, quando usamos application / x-www-form-urlencoded , o Spring não o entende como um RequestBody. Portanto, se quisermos usar isso, devemos remover a anotação @RequestBody .

Em seguida, tente o seguinte:

@RequestMapping(value = "/{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;
}

Observe que removeu a anotação @RequestBody

resposta : Solicitação Http Post com o tipo de conteúdo application / x-www-form-urlencoded não funcionando no Spring

Douglas Ribeiro
fonte
Obrigado! Resolve o problema. Agora me pergunto como removemos explicitamente o application/x-www-form-urlencoded?
kholofelo Maloma
1
não é necessário @kholofeloMaloma
Douglas Ribeiro
1
Se alguém se perguntou por que isso funciona sem nenhuma anotação, parece que o Spring lida com quaisquer argumentos não anotados como se eles tivessem @ModelAttribute, even though this behaviour is (sadly) not documented. And @ModelAttribute e entendesse x-www-form-urlencoded
cranphin
public ResponseEntity <?> getToken (MultiValueMap paramMap) IllegalArgumentException: tipo de argumento incompatível
withoutOne
Obrigado pela informação! Como um novato, estou me perguntando qual é a razão por trás desse comportamento pouco estranho do Spring para analisar a carga e vinculá-la ao objeto?
hafan96
66

Parece que agora você pode apenas marcar o parâmetro do método com @RequestParame ele fará o trabalho para você.

@PostMapping( "some/request/path" )
public void someControllerMethod( @RequestParam Map<String, String> body ) {
  //work with Map
}
Scadge
fonte
19

Adicione um cabeçalho à sua solicitação para definir o tipo de conteúdo para application / json

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

desta forma, o Spring sabe como analisar o conteúdo.

Agustín Almonte
fonte
Você também pode precisar adicionar um cabeçalho Aceitar ao seu comando: 'curl -vk -H "Aceitar: application / json" -H "Content-Type: application / json"' etc.
razvanone
1
você pode explicar como adicionar essa configuração ao meu formulário HTML?
Osama Al-Banna
9

Na primavera 5

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

    // import org.springframework.util.MultiValueMap;

    String datax = (String) body .getFirst("datax");
}
Edgardo Genini
fonte
Sim, com a inclusão de consumidor = MediaType.APPLICATION_FORM_URLENCODED_VALUE no mapeamento, você merece mais pontos senhor! obrigado! @RequestParam parece ser necessário agora para pegar MultiValueMap da solicitação
NemanjaT 01 de
3

A simples remoção da @RequestBodyanotação resolve o problema (testado no Spring Boot 2):

@RestController
public class MyController {

    @PostMapping
    public void method(@Valid RequestDto dto) {
       // method body ...
    }
}
Hamid Mohayeji
fonte
2

Eu escrevi sobre uma alternativa nesta resposta StackOverflow .

Lá escrevi passo a passo, explicando com código. O caminho mais curto:

Primeiro : escreva um objeto

Segundo : crie um conversor para mapear o modelo estendendo o AbstractHttpMessageConverter

Terceiro : diga para usar este conversor implementando um WebMvcConfigurer.class substituindo o método configureMessageConverters

Quarto e último: usando esta configuração de implementação no mapeamento dentro de seu controlador, consome = MediaType.APPLICATION_FORM_URLENCODED_VALUE e @RequestBody na frente de seu objeto.

Estou usando a bota de mola 2.

Marco Blos
fonte
0
@PostMapping(path = "/my/endpoint", consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE })
public ResponseEntity<Void> handleBrowserSubmissions(MyDTO dto) throws Exception {
    ...
}

Assim funciona para mim

Fernando Siqueira
fonte
0

Você pode tentar ligar o suporte no conversor do Spring

@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));
    }

}

Sergey Nemchinov
fonte
0

@RequestBody MultiValueMap paramMap

aqui Remova o @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";
} 

Curtiu isso

Yasiru Padmasiri
fonte
Embora este código possa resolver a questão, incluir uma explicação de como e por que isso resolve o problema realmente ajudaria a melhorar a qualidade de sua postagem e provavelmente resultaria em mais votos positivos. Lembre-se de que você está respondendo a pergunta para os leitores no futuro, não apenas para a pessoa que está perguntando agora. Por favor edite sua resposta para adicionar explicações e dar uma indicação do que limitações e premissas se aplicam.
Yunnosch