Le type de contenu 'application / x-www-form-urlencoded; charset = UTF-8' n'est pas pris en charge pour @RequestBody MultiValueMap


94

Basé sur la réponse au problème avec x-www-form-urlencoded avec Spring @Controller

J'ai écrit la méthode @Controller ci-dessous

@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 demande à laquelle échoue avec l'erreur ci-dessous

{
  "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 était beaucoup plus convivial, mais ne pouvait pas l'utiliser maintenant étant donné les restrictions pratiques ici]


Avez-vous ajouté consumes = {"application / x-www-form-urlencoded"} dans @RequestBody?
— shiladitya

1
Comment avez-vous exécuté la demande? ajoutez le code de (js, jquery, curl ou tout ce que vous utilisez).
— Nikolay Rusev

J'ai le même problème. Dans mon cas, j'utilise jquery ajax pour publier les données et les données sontJSON.stringify({"ordersToDownload":"00417002"}
— Arashsoft

Voici le code que j'utilise:$.ajax({url:"/myurl", type:"POST", data: JSON.stringify({"someAttribute":"someData"}) })
— Arashsoft

Réponses:


126

Le problème est que lorsque nous utilisons application / x-www-form-urlencoded , Spring ne le comprend pas comme un RequestBody. Donc, si nous voulons l'utiliser, nous devons supprimer l' annotation @RequestBody .

Ensuite, essayez ce qui suit:

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

Notez que l'annotation @RequestBody a été supprimée

Réponse : La demande de publication HTTP avec le type de contenu application / x-www-form-urlencoded ne fonctionne pas au printemps


Merci! Résout le problème. Maintenant, je me demande comment supprimer explicitement le application/x-www-form-urlencoded?
— kholofelo Maloma

1
il n'est pas nécessaire @kholofeloMaloma
— Douglas Ribeiro

Si quelqu'un se demandait pourquoi cela fonctionne sans aucune annotation, il semble que Spring gère tous les arguments non annotés comme s'ils avaient @ModelAttribute, even though this behaviour is (sadly) not documented. And @ModelAttribute comprenait x-www-form-urlencoded
— cranphin

public ResponseEntity <?> getToken (MultiValueMap paramMap) IllegalArgumentException: incompatibilité de type d'argument
— withoutOne

Merci pour l'info! En tant que débutant, je me demande quelle est la raison de ce petit comportement étrange de Spring pour analyser la charge utile et la lier à un objet?
— hafan96 le

66

Il semble que maintenant vous pouvez simplement marquer le paramètre de méthode avec @RequestParamet il fera le travail pour vous.

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

18

Ajoutez un en-tête à votre demande pour définir le type de contenu sur application / json

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

de cette façon, le printemps sait comment analyser le contenu.


Vous devrez peut-être également ajouter un en-tête Accept à votre commande: 'curl -vk -H "Accept: application / json" -H "Content-Type: application / json"' etc.
— razvanone

1
pouvez-vous expliquer comment ajouter ce paramètre à mon formulaire HTML?
— Osama Al-Banna

8

Au printemps 5

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

    // import org.springframework.util.MultiValueMap;

    String datax = (String) body .getFirst("datax");
}

Oui, avec l'inclusion de consumer = MediaType.APPLICATION_FORM_URLENCODED_VALUE dans la cartographie, vous méritez plus de points monsieur! Merci! Les coutures @RequestParam doivent être requises maintenant pour récupérer MultiValueMap à partir de la demande
— NemanjaT

2

Le simple fait de supprimer l' @RequestBodyannotation résout le problème (testé sur Spring Boot 2):

@RestController
public class MyController {

    @PostMapping
    public void method(@Valid RequestDto dto) {
       // method body ...
    }
}

1

J'ai écrit sur une alternative dans cette réponse StackOverflow .

Là, j'ai écrit étape par étape, en expliquant avec du code. Le chemin court:

Premièrement : écrire un objet

Deuxièmement : créer un convertisseur pour mapper le modèle en étendant le AbstractHttpMessageConverter

Troisièmement : dites au printemps d'utiliser ce convertisseur implémentant un WebMvcConfigurer.class remplaçant la méthode configureMessageConverters

Quatrième et dernier: l'utilisation de ce paramètre d'implémentation dans le mappage à l'intérieur de votre contrôleur consomme = MediaType.APPLICATION_FORM_URLENCODED_VALUE et @RequestBody devant votre objet.

J'utilise Spring Boot 2.


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

Cette façon fonctionne pour moi

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.