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.