Typ treści „application / x-www-form-urlencoded; charset = UTF-8” nie jest obsługiwany dla @RequestBody MultiValueMap

100

Na podstawie odpowiedzi na problem z x-www-form-urlencoded przy użyciu Spring @Controller

Poniżej napisałem metodę @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");
            }
    }

żądanie, które kończy się niepowodzeniem z powodu poniższego błędu

{
  "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 był o wiele bardziej przyjazny, ale nie mógł go teraz używać, biorąc pod uwagę praktyczne ograniczenia]

Somasundaram Sekar
źródło
Czy dodałeś Conses = {"application / x-www-form-urlencoded"} w @RequestBody?
shiladitya
1
Jak wykonałeś żądanie? dodaj kod (js, jquery, curl lub cokolwiek innego, czego używasz).
Nikolay Rusev
Mam ten sam problem. W moim przypadku używam jquery ajax do publikowania danych, a dane sąJSON.stringify({"ordersToDownload":"00417002"}
Arashsoft
Oto kod, którego używam:$.ajax({url:"/myurl", type:"POST", data: JSON.stringify({"someAttribute":"someData"}) })
Arashsoft
Sprawdź moją odpowiedź, podaj opis linku tutaj
Eshiett Oto-obong

Odpowiedzi:

130

Problem polega na tym, że kiedy używamy application / x-www-form-urlencoded , Spring nie rozumie tego jako RequestBody. Tak więc, jeśli chcemy tego użyć, musimy usunąć @RequestBody adnotację .

Następnie spróbuj wykonać następujące czynności:

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

Zwróć uwagę, że usunięto adnotację @RequestBody

Odpowiedź : Żądanie Http Post z typem zawartości application / x-www-form-urlencoded nie działa na wiosnę

Douglas Ribeiro
źródło
Dziękuję Ci! Rozwiązuje problem. Teraz zastanawiam się, w jaki sposób jawnie usunąć application/x-www-form-urlencoded?
kholofelo Maloma
1
nie jest to konieczne @kholofeloMaloma
Douglas Ribeiro
1
Jeśli ktoś zastanawiał się, dlaczego to działa bez adnotacji, wydaje się, że Spring obsługuje wszelkie argumenty bez adnotacji tak, jakby miały @ModelAttribute, even though this behaviour is (sadly) not documented. And @ModelAttribute rozumieć x-www-form-urlencoded
cranphin
public ResponseEntity <?> getToken (MultiValueMap paramMap) IllegalArgumentException: niezgodność typu argumentu
bezOne
Dzięki za informację! Jako nowicjusz zastanawiam się, jaki jest powód tego małego dziwnego zachowania Springa, aby przeanalizować ładunek i powiązać go z obiektem?
hafan96
66

Wygląda na to, że teraz możesz po prostu oznaczyć parametr metody za pomocą @RequestParami zrobi to za Ciebie.

@PostMapping( "some/request/path" )
public void someControllerMethod( @RequestParam Map<String, String> body ) {
  //work with Map
}
Scadge
źródło
18

Dodaj nagłówek do żądania, aby ustawić typ zawartości na application / json

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

w ten sposób wiosna wie, jak przeanalizować zawartość.

Agustin Almonte
źródło
Może być konieczne dodanie nagłówka Accept do polecenia: 'curl -vk -H "Accept: application / json" -H "Content-Type: application / json"' itd.
razvanone
1
czy możesz wyjaśnić, jak dodać to ustawienie do mojego formularza HTML?
Osama Al-Banna
9

Wiosną 5

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

    // import org.springframework.util.MultiValueMap;

    String datax = (String) body .getFirst("datax");
}
Edgardo Genini
źródło
Tak, z uwzględnieniem konsumenta = MediaType.APPLICATION_FORM_URLENCODED_VALUE w mapowaniu, zasługujesz na więcej punktów! Dziękuję Ci! @RequestParam będzie teraz wymagane do odebrania mapy MultiValueMap z żądania
NemanjaT
3

Samo usunięcie @RequestBodyadnotacji rozwiązuje problem (testowane na Spring Boot 2):

@RestController
public class MyController {

    @PostMapping
    public void method(@Valid RequestDto dto) {
       // method body ...
    }
}
Hamid Mohayeji
źródło
2

O alternatywie pisałem w tej odpowiedzi StackOverflow .

Tam pisałem krok po kroku, wyjaśniając kodem. Krótka droga:

Po pierwsze : napisz obiekt

Po drugie : utwórz konwerter do mapowania modelu rozszerzającego AbstractHttpMessageConverter

Trzeci : powiedz, by wiosna użyła tego konwertera implementującego WebMvcConfigurer.class nadpisującego metodę configureMessageConverters

Czwarty i ostatnie: używając tego ustawienia implementacji w mapowaniu wewnątrz kontrolera, konsumuje = MediaType.APPLICATION_FORM_URLENCODED_VALUE i @RequestBody przed obiektem.

Używam buta sprężynowego 2.

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

U mnie to działa

Fernando Siqueira
źródło
0

Możesz spróbować włączyć obsługę w konwerterze Springa

@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // add converter suport Content-Type: 'application/x-www-form-urlencoded'
        converters.stream()
                .filter(AllEncompassingFormHttpMessageConverter.class::isInstance)
                .map(AllEncompassingFormHttpMessageConverter.class::cast)
                .findFirst()
                .ifPresent(converter -> converter.addSupportedMediaTypes(MediaType.APPLICATION_FORM_URLENCODED_VALUE));
    }

}

Sergey Nemchinov
źródło
0

@RequestBody MultiValueMap paramMap

tutaj Usuń adnotację @RequestBody

@RequestMapping(value = "/signin",method = RequestMethod.POST)
public String createAccount(@RequestBody LogingData user){
    logingService.save(user);
    return "login";
}




@RequestMapping(value = "/signin",method = RequestMethod.POST)
public String createAccount( LogingData user){
    logingService.save(user);
    return "login";
} 

tak

Yasiru Padmasiri
źródło
Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia.
Yunnosch