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]

Somasundaram Sekar
la source
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
Vérifiez ma réponse, entrez la description du lien ici
Eshiett Oto-obong

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

Douglas Ribeiro
la source
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
}
Scadge
la source
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.

Agustin Almonte
la source
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");
}
Edgardo Genini
la source
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 ...
    }
}
Hamid Mohayeji
la source
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.

Marco Blos
la source
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

Fernando Siqueira
la source