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í]


¿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

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


¡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
}

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.


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

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 ...
    }
}

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.


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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.