Żądanie Spring JSON uzyskuje 406 (niedopuszczalne)

85

to jest mój javascript:

    function getWeather() {
        $.getJSON('getTemperature/' + $('.data option:selected').val(), null, function(data) {
            alert('Success');                               
        });
    }

to jest mój kontroler:

@RequestMapping(value="/getTemperature/{id}", headers="Accept=*/*", method = RequestMethod.GET)
@ResponseBody
public Weather getTemparature(@PathVariable("id") Integer id){
    Weather weather = weatherService.getCurrentWeather(id);
        return weather;
}

spring-servlet.xml

<context:annotation-config />
<tx:annotation-driven />

Pojawia się ten błąd:

GET http://localhost:8080/web/getTemperature/2 406 (Not Acceptable)

Nagłówki:

Nagłówki odpowiedzi

Server  Apache-Coyote/1.1
Content-Type    text/html;charset=utf-8
Content-Length  1070
Date    Sun, 18 Sep 2011 17:00:35 GMT

Nagłówki żądań

Host    localhost:8080
User-Agent  Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0.2) Gecko/20100101 Firefox/6.0.2
Accept  application/json, text/javascript, */*; q=0.01
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip, deflate
Accept-Charset  ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection  keep-alive
X-Requested-With    XMLHttpRequest
Referer http://localhost:8080/web/weather
Cookie  JSESSIONID=7D27FAC18050ED84B58DAFB0A51CB7E4

Ciekawa uwaga:

Otrzymuję błąd 406, ale zapytanie hibernacji działa w międzyczasie. Oto, co mówi dziennik tomcat, za każdym razem, gdy zmieniam wybór w dropbox:

 select weather0_.ID as ID0_0_, weather0_.CITY_ID as CITY2_0_0_, weather0_.DATE as DATE0_0_, weather0_.TEMP as TEMP0_0_ from WEATHER weather0_ where weather0_.ID=?

Jaki może być problem? W SO były dwa podobne pytania, wypróbowałem tam wszystkie akceptowane wskazówki, ale chyba nie zadziałały ...

Jakieś sugestie? Zapraszam do zadawania pytań ...

Jaanus
źródło

Odpowiedzi:

107

406 Niedopuszczalne

Zasób zidentyfikowany w żądaniu może generować tylko jednostki odpowiedzi, których cechy treści są niedopuszczalne zgodnie z nagłówkami akceptacji przesłanymi w żądaniu.

Więc twój nagłówek akceptacji żądania to application / json i twój kontroler nie jest w stanie tego zwrócić. Dzieje się tak, gdy nie można znaleźć prawidłowego HTTPMessageConverter spełniającego wartość zwracaną @ResponseBody z adnotacjami. HTTPMessageConverter są automatycznie rejestrowane podczas korzystania z <mvc:annotation-driven>określonych bibliotek stron trzecich w ścieżce klas.

Albo nie masz poprawnej biblioteki Jacksona w swojej ścieżce klas, albo nie użyłeś <mvc:annotation-driven>dyrektywy.

Pomyślnie zreplikowałem twój scenariusz i działał dobrze przy użyciu tych dwóch bibliotek i bez headers="Accept=*/*"dyrektywy.

  • jackson-core-asl-1.7.4.jar
  • jackson-mapper-asl-1.7.4.jar
Villu Sepman
źródło
Nie, to nie był problem, sprawdź moją odpowiedź.
Jaanus,
Jeśli skonfigurowanie HttpMessageConverters ręcznie rozwiązało problem, użycie mvc: annotation-Based zrobiłoby to samo, co automatycznie konfiguruje konwertery i HandlerAdapters (HA). Zauważ, że jeśli skonfigurujesz dowolne HA jawnie, anuluje to wszystkie inne ustawienia domyślne.
Villu Sepman,
Hmm, co mvctam jest? Użyłem <tx:annotation-driven />i tx jestxmlns:tx="http://www.springframework.org/schema/tx"
Jaanus
1
Masz coś takiego jak: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">i spring-web-3.0.x i spring-webmvc-3.0.x jars?
Villu Sepman
1
Ach, nie miałem tam tego schematu… ale dzięki, to mi pomogło. Myślałem, że to tx:annotation-drivento samo co mvc:annotation-drivecoś.
Jaanus
74

Miałem ten sam problem, od najnowszej wiosny 4.1.1 musisz dodać kolejne słoiki do pom.xml.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.4.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.4.1.1</version>
</dependency>

upewnij się również, że masz następujący słoik:

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-asl</artifactId>
    <version>1.9.13</version>
</dependency>

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>

406 Spring MVC Json, niedopuszczalne zgodnie z żądaniem „akceptacji” nagłówków

AKB
źródło
Ta odpowiedź jest najlepszą odpowiedzią w wersji świadomej Mavena i działa idealnie! Wyjątki Maven mogą być bardziej jasne, co faktycznie dzieje się pod maską.
Cotta
4
Czy możesz podać, gdzie jest to udokumentowane w oficjalnej dokumentacji Springs? Skąd ktoś może wiedzieć, że to jest problem?
Adelin
Musisz tylko określić zależności do jackson-databind i jackson-mapper-asl, pozostałe dwie są zależnościami przechodnimi i zostaną rozwiązane i tak.
anre
1
To działało tylko dla mnie po dodaniu dwóch drugich zależności. Dzięki.
DocWatson
Zdecydowanie nie potrzebujesz obu. Wiosna doda MappingJacksonHttpMessageConverterdla Jacksona 1 i MappingJackson2HttpMessageConverterdla Jacksona 2. Każdy z nich jest wystarczająco dobry, aby serializować / deserializować JSON. Potrzebujesz tylko jednego (wybierz Jackson 2, ponieważ jest bardziej bogaty w funkcje).
Sotirios Delimanolis
16

Jest jeszcze jeden przypadek, w którym ten status zostanie zwrócony: jeśli program mapujący Jackson nie może dowiedzieć się, jak serializować Twój bean. Na przykład, jeśli masz dwie metody akcesorów dla tej samej właściwości logicznej isFoo()i getFoo().

Co się dzieje jest to, że sprężyny MappingJackson2HttpMessageConverter nazywa Jacksona StdSerializerProvider aby sprawdzić, czy można go przekształcić obiekt. Na dole łańcucha połączeń, StdSerializerProvider._createAndCacheUntypedSerializerrzuca JsonMappingExceptionz komunikatem informacyjnym. Jednak ten wyjątek zostaje pochłonięty przez StdSerializerProvider._createAndCacheUntypedSerializer, co mówi Springowi, że nie może przekonwertować obiektu. Po wyczerpaniu się konwerterów Spring zgłasza, że ​​nie otrzymuje Acceptnagłówka, którego mógłby użyć, co oczywiście jest fałszywe, gdy go podajesz */*.

W tym zachowaniu jest błąd , ale zostało ono zamknięte jako „nie można odtworzyć”: wywoływana metoda nie deklaruje, że może zgłosić, więc połknięcie wyjątków jest najwyraźniej odpowiednim rozwiązaniem (tak, to był sarkazm). Niestety, Jackson nie ma żadnego logowania ... i jest wiele komentarzy w bazie kodów, które tego życzą, więc podejrzewam, że nie jest to jedyna ukryta pułapka.

kdgregory
źródło
Dziękuję bardzo! Jestem nowy w Spring MVC i naprawdę ciężko mi było dowiedzieć się, jak zwrócić JSON. Wszyscy wymieniają brakujące adnotacje @ResponseBody i zależności Jacksona jako przyczynę błędów 406. W moim przypadku okazuje się, że brakowało mi metody akcesora dla pola publicznego należącego do obiektu, który chciałem zwrócić jako JSON.
Anthony Jack,
Dzięki @kdgregory! Zapomniałem dodać getter / setter dla pola. Dodanie ich rozwiązało ten problem.
Rubens Mariuzzo
16

Miałem ten sam problem, moja metoda kontrolera jest wykonywana, ale odpowiedzią jest błąd 406. Debugowałem AbstractMessageConverterMethodProcessor#writeWithMessageConvertersi stwierdziłem, że ta metoda ContentNegotiationManager#resolveMediaTypeszawsze zwraca, text/htmlco nie jest obsługiwane przez MappingJacksonHttpMessageConverter. Problem w tym, że org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategydziała wcześniej niż org.springframework.web.accept.HeaderContentNegotiationStrategy, a rozszerzenie mojego żądania /get-clients.htmljest przyczyną mojego problemu z błędem 406. Właśnie zmieniłem adres URL żądania na /get-clients.

atott
źródło
Witam atott, mam ten sam problem i twoja wskazówka dotycząca zmiany rozszerzenia wniosku rozwiązała mój problem. Wielkie dzięki za udostępnienie rozwiązania !!
jherranzm
W moim przypadku był to identyfikator ścieżki spoczynkowej z rozszerzeniem (w teście), który spowodował 406 z tego samego powodu, podczas gdy normalny kontroler działa (nawet jeśli miałbyś użyć rozszerzenia w identyfikatorze ścieżki spoczynkowej).
Jur_
9

Upewnij się, że jarw ścieżce klasy występują następujące 2 znaki.

Jeśli brakuje jednego lub obu, pojawi się ten błąd.

jackson-core-asl-1.9.X.jar jackson-mapper-asl-1.9.X.jar
Raju Rathi
źródło
6

Wreszcie znalazłem odpowiedź stąd:

Mapowanie restful żądań ajax na wiosnę

Cytuję:

Adnotacje @ RequestBody / @ ResponseBody nie używają normalnych programów do rozpoznawania widoku, używają własnych HttpMessageConverters. Aby użyć tych adnotacji, należy skonfigurować te konwertery w AnnotationMethodHandlerAdapter, zgodnie z opisem w odwołaniu (prawdopodobnie potrzebujesz MappingJacksonHttpMessageConverter).

Jaanus
źródło
3

Sprawdź <mvc:annotation-driven />w pliku dispatcherservlet.xml, jeśli nie, dodaj go. I dodaj

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-asl</artifactId>
    <version>1.9.13</version>
</dependency>

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>

te zależności w pliku pom.xml

SIEDMIODNIOWA ŻAŁOBA
źródło
2
<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-base</artifactId>
    <version>2.6.3</version>
</dependency>
Rajan
źródło
2
Chociaż ten kod może odpowiedzieć na pytanie, dostarczenie dodatkowego kontekstu dotyczącego tego, jak i / lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi.
Francesco Menzani
2

Prawdopodobnie nikt nie przewija tak daleko, ale żadne z powyższych rozwiązań nie rozwiązało tego za mnie, ale zrobienie wszystkich moich metod gettera public.

Zostawiłem widoczność mojego gettera na prywatnym opakowaniu; Jackson zdecydował, że nie może ich znaleźć i wysadził w powietrze. (Użycie @JsonAutoDetect(getterVisibility=NON_PRIVATE)tylko częściowo naprawiło to.

Hazel Troost
źródło
To był dokładnie mój problem. Zmieniam moje setery z publicznego na chroniony i Jackson przestał działać.
JuanMiguel
Ten sam problem, użyłem AbstractMap.SimpleImmutableEntry a następnie obniżyłem do AbstractMap.SimpleEntry, nadal nie ma kości, ponieważ nie ma setera dla klucza. Gone pojo w tej sprawie.
Robert Bain
2

Upewnij się, że wysłany obiekt (w tym przypadku Weather) zawiera getter / setter

Riadh
źródło
1

W kontrolerze adnotacja treści odpowiedzi nie powinna znajdować się na zwracanym typie, a nie metodzie, jak na przykład:

@RequestMapping(value="/getTemperature/{id}", headers="Accept=*/*", method = RequestMethod.GET)
public @ResponseBody Weather getTemparature(@PathVariable("id") Integer id){
    Weather weather = weatherService.getCurrentWeather(id);
        return weather;
}

Użyłbym również surowej funkcji jquery.ajax i upewniłbym się, że contentType i dataType są ustawione poprawnie.

Z innej strony uważam, że obsługa sprężyny json jest raczej problematyczna. Było łatwiej, gdy robiłem to wszystko sam za pomocą stringów i GSON.

NimChimpsky
źródło
Umiejscowienie @ResponseBodynie powinno mieć znaczenia ... Przyjrzę się GSON ... ale nadal chciałbym, aby ten JSON działał, jeśli to możliwe.
Jaanus,
1

Jak wspomniał @atott .

Jeśli dodałeś najnowszą wersję Jacksona do swojego pom.xml i ze Spring 4.0 lub nowszą, używając @ResponseBodyswojej metody akcji i @RequestMappingskonfigurowanej z produces="application/json;charset=utf-8", jednak nadal masz 406 (Nie do przyjęcia), myślę, że musisz spróbować tego w Twoja konfiguracja kontekstu MVC DispatcherServlet:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
</bean>

W ten sposób ostatecznie rozwiązałem mój problem.

Kruk
źródło
1

Wiosna 4.3.10: Użyłem poniższych ustawień, aby rozwiązać problem.

Krok 1: Dodaj poniższe zależności

    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.6.7</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.6.7</version>
</dependency>
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-asl</artifactId>
    <version>1.9.13</version>
</dependency>
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>

Krok 2: Dodaj poniższe w konfiguracji kontekstu MVC DispatcherServlet:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>

<bean id="contentNegotiationManager"
    class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false"/>
    <property name="favorParameter" value="true"/>
    <property name="ignoreAcceptHeader" value="false" />
</bean>

Od wiosny 3.2, zgodnie z domyślną konfiguracją, favorPathExtension jest ustawiony jako true, z tego powodu, jeśli żądanie uri ma jakiekolwiek odpowiednie rozszerzenia, takie jak .htmspring, nada priorytet rozszerzeniu. W kroku 2 dodałem komponent bean contentNegotiationManager, aby to zastąpić.

Kevin Sebastian Fernandez
źródło
1

Miałem ten sam problem, ponieważ brakowało mi adnotacji @EnableWebMvc. (Wszystkie moje konfiguracje wiosenne są oparte na adnotacjach, odpowiednik XML to mvc: annotation-based)

jambriz
źródło
0

upewnij się, że masz poprawną wersję jackson w swojej ścieżce klas

joyfun
źródło
Dodałem jackson-all-1.8.5.jar do mojego WEB-INF/libfolderu, ale nadal ten sam problem: /
Jaanus
0

Sprawdź, jak @joyfun zrobił to dla poprawnej wersji jackson, ale także sprawdź nasze nagłówki ... Zaakceptuj / może nie być przesłane przez klienta ... użyj firebuga lub odpowiednika, aby sprawdzić, co faktycznie wysyła twoje żądanie get. Myślę, że atrybut nagłówków adnotacji / może / sprawdza literały, chociaż nie jestem w 100% pewien.

Dave G.
źródło
Dodałem nagłówki z firebuga do głównego postu. Czy wszystko w porządku?
Jaanus,
0

Poza oczywistymi problemami miałem inny, którego nie mogłem naprawić, niezależnie od włączenia wszystkich możliwych plików JAR, zależności i adnotacji w serwlecie Spring. Ostatecznie stwierdziłem, że mam złe rozszerzenie pliku, co oznacza, że ​​miałem dwa oddzielne serwlety działające w tym samym kontenerze i musiałem mapować do różnych rozszerzeń plików, w których jeden to „.do”, a drugi używany do subskrypcji miał losową nazwę ”. pod". Wszystko w porządku, ale SUB jest prawidłowym rozszerzeniem pliku używanym normalnie w plikach napisów do filmów i dlatego Tomcat nadpisywał nagłówek i zwracał coś w rodzaju "text / x-dvd.sub ...", więc wszystko było w porządku, ale aplikacja oczekiwała JSON, ale pobierała napisy więc wszystko, co musiałem zrobić, to zmienić mapowanie w moim web.xmlpliku, które dodałem:

<mime-mapping>
    <extension>sub</extension>
    <mime-type>application/json</mime-type>
</mime-mapping>
Alex Rashkov
źródło
0

Miałem ten sam problem, niestety żadne rozwiązanie tutaj nie rozwiązało mojego problemu, ponieważ mój problem był z innej klasy.

Najpierw sprawdziłem, czy wszystkie zależności są na miejscu, zgodnie z sugestią @bekur, a następnie sprawdziłem, czy żądanie / odpowiedź, które wędruje od klientów do serwera, wszystkie nagłówki są na miejscu i są odpowiednio ustawione przez Jquery. Następnie sprawdziłemRequestMappingHandlerAdapter MessageConverters i wszystkie 7 z nich są na miejscu. Naprawdę zacząłem nienawidzić Spring! Następnie zaktualizowałem ze Spring 4.0.6.RELEASEdo 4.2.0.RELEASEOtrzymałem inną odpowiedź niż powyższe. To byłoRequest processing failed; nested exception is java.lang.IllegalArgumentException: No converter found for return value of type

Oto moja metoda kontrolera

  @RequestMapping(value = "/upload", method = RequestMethod.POST,produces = "application/json")
    public ResponseEntity<UploadPictureResult> pictureUpload(FirewalledRequest initialRequest) {

        DefaultMultipartHttpServletRequest request = (DefaultMultipartHttpServletRequest) initialRequest.getRequest();

        try {
            Iterator<String> iterator = request.getFileNames();

            while (iterator.hasNext()) {
                MultipartFile file = request.getFile(iterator.next());
                session.save(toImage(file));
            }
        } catch (Exception e) {
            return new ResponseEntity<UploadPictureResult>(new UploadPictureResult(),HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return new ResponseEntity<UploadPictureResult>(new UploadPictureResult(), HttpStatus.OK);
    } 




    public class UploadPictureResult extends WebResponse{

    private List<Image> images;

    public void setImages(List<Image> images) {
        this.images = images;
    }
}






    public class WebResponse implements Serializable {


    protected String message;

    public WebResponse() {
    }

    public WebResponse(String message) {

        this.message = message;
    }


    public void setMessage(String message) {
        this.message = message;
    }
}

Rozwiązaniem było sprawienie, by UploadPictureResult nie rozszerzał WebResponse

Z jakiegoś powodu Spring nie był w stanie określić, jak przekonwertować UploadPictureReslt po rozszerzeniu WebResponse

Adelin
źródło
0
<dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.8.0</version>
    </dependency>

nie używam uwierzytelniania ssl, a ten jackson-databind zawiera pliki jackson-core.jar i jackson-databind.jar, a następnie zmień zawartość RequestMapping w następujący sposób:

@RequestMapping(value = "/id/{number}", produces = "application/json; charset=UTF-8", method = RequestMethod.GET)
public @ResponseBody Customer findCustomer(@PathVariable int number){
    Customer result = customerService.findById(number);
    return result;
}

uwaga: jeśli twoje produkty nie są typu „application / json”, a ja nie zauważyłem tego i otrzymałem błąd 406, to może ci pomóc.

Crabime
źródło
0

sprawdź ten wątek. spring mvc restcontroller return json string p / s: powinieneś dodać konfigurację mapowania jack son do swojej klasy WebMvcConfig

@Override protected void configureMessageConverters( List<HttpMessageConverter<?>> converters) { // put the jackson converter to the front of the list so that application/json content-type strings will be treated as JSON converters.add(new MappingJackson2HttpMessageConverter()); // and probably needs a string converter too for text/plain content-type strings to be properly handled converters.add(new StringHttpMessageConverter()); }

Anh Lam
źródło
0

To jest odpowiedź na aktualizację dla springVersion = 5.0.3.RELEASE.

Te powyższe odpowiedzi będą działały tylko w starszej wersji springVersion <4.1 . na ostatnią wiosnę musisz dodać następujące zależności w pliku gradle:

compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: fasterxmljackson
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: fasterxmljackson

fasterxmljackson=2.9.4

Mam nadzieję, że będzie to pomocne dla osób korzystających z najnowszej wersji wiosennej.

Paraneetharan Saravanaperumal
źródło
-3

Czy możesz usunąć element nagłówków w @RequestMapping i spróbować ...

Lubić


@RequestMapping(value="/getTemperature/{id}", method = RequestMethod.GET)

Wydaje mi się, że wiosna raczej sprawdza „zawiera” niż dokładne dopasowanie dla akceptowanych nagłówków. Mimo to warto spróbować usunąć element nagłówków i sprawdzić.

stratwine
źródło
Usunąłem, ale nadal błąd. Przy okazji, kiedy patrzę w dziennik tomcat, wtedy zapytanie z tym zostało weatherService.getCurrentWeather(id);"aktywowane" ... więc coś działa ... czy to możliwe, że pojawia się 406 i Hibernate SQL select działa w tym samym czasie?
Jaanus,
Spróbuj tego, który powinien działać. Dodaj tę adnotację na kontrolerze @RequestMapping (method = RequestMethod.GET, headers = {"Accept = text / xml, application / json"})
sats