El tipo de contenido 'application / x-www-form-urlencoded; charset = UTF-8' no es compatible con @RequestBody MultiValueMap

95

Basado en la respuesta al problema con x-www-form-urlencoded con Spring @Controller

He escrito el siguiente método @Controller

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

la solicitud a la que falla con el siguiente 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"
}

[PD: Jersey era mucho más amigable, pero no podía usarlo ahora dadas las restricciones prácticas aquí]

Somasundaram Sekar
fuente
¿Agregaste consumes = {"application / x-www-form-urlencoded"} en @RequestBody?
Shiladitya
1
¿Cómo ejecutó la solicitud? agregue el código de (js, jquery, curl o lo que sea que use).
Nikolay Rusev
Tengo el mismo problema. En mi caso, uso jquery ajax para publicar los datos y los datos sonJSON.stringify({"ordersToDownload":"00417002"}
Arashsoft
Este es el código que uso: $.ajax({url:"/myurl", type:"POST", data: JSON.stringify({"someAttribute":"someData"}) })
Arashsoft
Verifique mi respuesta ingrese la descripción del enlace aquí
Eshiett Oto-obong

Respuestas:

126

El problema es que cuando usamos application / x-www-form-urlencoded , Spring no lo entiende como RequestBody. Entonces, si queremos usar esto, debemos eliminar la anotación @RequestBody .

Luego intente lo siguiente:

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

Tenga en cuenta que eliminó la anotación @RequestBody

responder : La solicitud Http Post con aplicación de tipo de contenido / x-www-form-urlencoded no funciona en Spring

Douglas Ribeiro
fuente
¡Gracias! Resuelve el problema. Ahora me pregunto cómo eliminamos explícitamente el application/x-www-form-urlencoded?
kholofelo Maloma
1
no es necesario @kholofeloMaloma
Douglas Ribeiro
Si alguien se pregunta por qué esto funciona sin ninguna anotación, parece que Spring maneja los argumentos no anotados como si tuvieran @ModelAttribute, even though this behaviour is (sadly) not documented. And @ModelAttribute sí entiende x-www-form-urlencoded
cranphin
public ResponseEntity <?> getToken (MultiValueMap paramMap) IllegalArgumentException: no coincide el tipo de argumento
withoutOne
Gracias por la info! Como novato, me pregunto cuál es la razón detrás de este pequeño comportamiento extraño para que Spring analice la carga útil y la vincule al objeto.
hafan96
66

Parece que ahora puede marcar el parámetro del método con @RequestParamy hará el trabajo por usted.

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

Agregue un encabezado a su solicitud para establecer el tipo de contenido en application / json

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

de esta manera Spring sabe cómo analizar el contenido.

Agustín Almonte
fuente
Es posible que también deba agregar un encabezado Accept a su comando: 'curl -vk -H "Accept: application / json" -H "Content-Type: application / json"' etc.
razvanone
1
¿Puede explicar cómo agregar esta configuración a mi formulario HTML?
Osama Al-Banna
8

En 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
fuente
Sí, con la inclusión de consumer = MediaType.APPLICATION_FORM_URLENCODED_VALUE en el mapeo, ¡se merece más puntos, señor! ¡gracias! Las costuras de @RequestParam deben ser necesarias ahora para recoger MultiValueMap de la solicitud
NemanjaT
2

Simplemente eliminar la @RequestBodyanotación resuelve el problema (probado en Spring Boot 2):

@RestController
public class MyController {

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

Escribí sobre una alternativa en esta respuesta de StackOverflow .

Allí escribí paso a paso, explicando con código. El camino corto:

Primero : escribe un objeto

Segundo : cree un convertidor para mapear el modelo extendiendo AbstractHttpMessageConverter

Tercero : dígale a Spring que use este convertidor implementando una clase WebMvcConfigurer.class que anula el método configureMessageConverters

Cuarto y último: usando esta configuración de implementación en el mapeo dentro de su controlador, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE y @RequestBody frente a su objeto.

Estoy usando Spring Boot 2.

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

De esa manera funciona para mi

Fernando Siqueira
fuente