Richiesta JSON Spring che ottiene 406 (non accettabile)


85

questo è il mio javascript:

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

questo è il mio controller:

@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 />

Ottenere questo errore:

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

Intestazioni:

Intestazioni di risposta

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

Richiedi intestazioni

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

Nota interessante:

Ottengo l'errore 406, ma nel frattempo la query di ibernazione funziona. Questo è ciò che dice il registro di Tomcat, ogni volta che cambio la selezione nella casella personale:

 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=?

Quale potrebbe essere il problema? C'erano due domande simili in SO prima, ho provato tutti i suggerimenti accettati lì, ma non hanno funzionato immagino ...

Eventuali suggerimenti? Sentiti libero di fare domande ...

Risposte:


107

406 Non accettabile

La risorsa identificata dalla richiesta è in grado di generare solo entità di risposta che hanno caratteristiche di contenuto non accettabili in base alle intestazioni di accettazione inviate nella richiesta.

Quindi, l'intestazione di accettazione della tua richiesta è application / json e il tuo controller non è in grado di restituirla. Ciò accade quando non è possibile trovare il HTTPMessageConverter corretto per soddisfare il valore di ritorno annotato @ResponseBody. HTTPMessageConverter vengono registrati automaticamente quando si utilizza <mvc:annotation-driven>, date alcune librerie di parti 3-d nel classpath.

O non hai la libreria Jackson corretta nel tuo classpath, o non hai usato la <mvc:annotation-driven>direttiva.

Ho replicato con successo il tuo scenario e ha funzionato bene usando queste due librerie e nessuna headers="Accept=*/*"direttiva.

  • jackson-core-asl-1.7.4.jar
  • jackson-mapper-asl-1.7.4.jar

No, non era questo il problema, controlla la mia risposta.
Jaanus

Se la configurazione di HttpMessageConverters ha risolto manualmente il problema, l'uso di mvc: annotation-driven farebbe lo stesso in quanto configura automaticamente i convertitori e gli HandlerAdapters (HA). Si noti che se si configura esplicitamente qualsiasi HA, verranno annullati tutti gli altri valori predefiniti.
Villu Sepman

Hmm, cosa c'è mvclì? Ho usato <tx:annotation-driven />e la trasmissione èxmlns:tx="http://www.springframework.org/schema/tx"
Jaanus

1
Hai qualcosa come: <?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">e i vasi spring-web-3.0.xe spring-webmvc-3.0.x?
Villu Sepman

1
Ah, non avevo quella posizione schematica lì ... ma grazie, questo mi ha aiutato. Ho pensato che tx:annotation-drivenfosse lo stesso di mvc:annotation-driveo smthin.
Jaanus

74

Ho avuto lo stesso problema, con l'ultima primavera 4.1.1 in poi è necessario aggiungere i seguenti jar a 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>

assicurati anche di avere il seguente barattolo:

<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, non accettabile in base alle intestazioni "accetta" della richiesta


Questa risposta è la versione consapevole di Maven della risposta principale e funziona perfettamente! Le eccezioni di Maven potrebbero essere più chiare su ciò che sta effettivamente accadendo sotto il cofano.
Cotta

4
Potete fornire dove questo è documentato sulla documentazione ufficiale di Springs? Come può qualcuno sapere che questo è il problema?
Adelin

Devi solo specificare le dipendenze da jackson-databind e jackson-mapper-asl, le altre due sono dipendenze transitive e verranno comunque risolte.
anre

1
Questo ha funzionato solo per me dopo aver aggiunto le seconde due dipendenze. Grazie.
DocWatson

Sicuramente non hai bisogno di entrambi. La primavera si aggiungerà MappingJacksonHttpMessageConverterper Jackson 1 e MappingJackson2HttpMessageConverterper Jackson 2. Ognuno di questi è abbastanza buono per serializzare / deserializzare JSON. Ne hai solo bisogno (vai con Jackson 2 poiché è più ricco di funzionalità).
Sotirios Delimanolis

16

C'è un altro caso in cui verrà restituito questo stato: se il mapper Jackson non riesce a capire come serializzare il tuo bean. Ad esempio, se si dispone di due metodi di accesso per la stessa proprietà booleana, isFoo()e getFoo().

Quello che sta succedendo è che la Primavera MappingJackson2HttpMessageConverter chiama di Jackson StdSerializerProvider per vedere se è in grado di convertire l'oggetto. In fondo alla catena di chiamate, StdSerializerProvider._createAndCacheUntypedSerializergenera un JsonMappingExceptioncon un messaggio informativo. Tuttavia, questa eccezione viene inghiottita da StdSerializerProvider._createAndCacheUntypedSerializer, che dice a Spring che non può convertire l'oggetto. Avendo esaurito i convertitori, Spring riferisce che non gli viene data Acceptun'intestazione che può utilizzare, il che ovviamente è fasullo quando lo dai */*.

C'è un bug per questo comportamento, ma è stato chiuso perché "non può riprodursi": il metodo che viene chiamato non dichiara che può lanciare, quindi inghiottire eccezioni è apparentemente una soluzione appropriata (sì, quello era sarcasmo). Sfortunatamente, Jackson non ha alcun registro ... e ci sono molti commenti nella base di codice che lo desiderano, quindi sospetto che questo non sia l'unico trucco nascosto.


Grazie mille! Sono nuovo di Spring MVC e ho avuto davvero difficoltà a capire come restituire JSON. Tutti menzionano le annotazioni @ResponseBody mancanti e le dipendenze di Jackson come causa di errori 406. Nel mio caso, risulta che mi mancava solo un metodo di accesso per un campo pubblico appartenente all'oggetto che volevo restituire come JSON.
Anthony Jack,

Grazie @kdgregory! Ho dimenticato di aggiungere getter / setter per un campo. L'aggiunta di loro ha risolto questo problema.
Rubens Mariuzzo

16

Ho avuto lo stesso problema, il mio metodo del controller viene eseguito ma la risposta è Errore 406. Ho eseguito il debug AbstractMessageConverterMethodProcessor#writeWithMessageConverterse ho scoperto che il metodo ContentNegotiationManager#resolveMediaTypesrestituisce sempre text/htmlche non è supportato da MappingJacksonHttpMessageConverter. Il problema è che org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategyfunziona prima di org.springframework.web.accept.HeaderContentNegotiationStrategye l'estensione della mia richiesta /get-clients.htmlè la causa del mio problema con l'errore 406. Ho appena cambiato l'URL della richiesta in /get-clients.


Ciao atott, ho lo stesso problema e il tuo consiglio sulla modifica dell'estensione della richiesta ha risolto il mio problema. Grazie mille per aver condiviso la tua soluzione !!
jherranzm

Nel mio caso è stato un rest path id con un'estensione al suo interno (nel test) che ha causato il 406 per lo stesso motivo, mentre il normale controller funziona (anche se dovessi usare un'estensione nel rest path id).
Jur_

9

Assicurati che i seguenti 2 jarsiano presenti nel percorso classe.

Se uno o entrambi mancano, verrà visualizzato questo errore.

jackson-core-asl-1.9.X.jar jackson-mapper-asl-1.9.X.jar

6

Finalmente ho trovato la risposta da qui:

Mappatura delle richieste ajax riposanti alla primavera

Quoto:

Le annotazioni @ RequestBody / @ ResponseBody non utilizzano normali risolutori di viste, ma utilizzano i propri HttpMessageConverters. Per utilizzare queste annotazioni, è necessario configurare questi convertitori in AnnotationMethodHandlerAdapter, come descritto nel riferimento (probabilmente è necessario MappingJacksonHttpMessageConverter).


3

Controlla <mvc:annotation-driven />in dispatcherservlet.xml, se non aggiungilo. E aggiungi

<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>

queste dipendenze nel tuo pom.xml


2
<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-base</artifactId>
    <version>2.6.3</version>
</dependency>

2
Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo su come e / o perché risolve il problema migliorerebbe il valore a lungo termine della risposta.
Francesco Menzani

2

Probabilmente nessuno sta scorrendo fino a questo punto, ma nessuna delle soluzioni precedenti l'ha risolto per me, ma tutti i miei metodi getter lo hanno publicfatto.

Avevo lasciato la mia visibilità getter a package-private; Jackson ha deciso che non poteva trovarli ed è esploso. (Utilizzando @JsonAutoDetect(getterVisibility=NON_PRIVATE)solo parzialmente risolto.


Quello era esattamente il mio problema. Ho cambiato i miei setter da pubblici a protetti e Jackson ha smesso di lavorare.
JuanMiguel

Stesso problema qui, stavo usando AbstractMap.SimpleImmutableEntryquindi declassato a AbstractMap.SimpleEntry, ancora nessun dado in quanto non ha un setter per la chiave. Andato pojo su questo.
Robert Bain

2

Assicurati che l'oggetto inviato (Weather in questo caso) contenga getter / setter


1

Nel controller, l'annotazione del corpo della risposta non dovrebbe essere sul tipo restituito e non sul metodo, in questo modo:

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

Utilizzerei anche la funzione jquery.ajax non elaborata e mi assicurerei che contentType e dataType siano impostati correttamente.

In una nota diversa, trovo la gestione della molla di json piuttosto problematica. È stato più facile quando ho fatto tutto da solo usando le corde e GSON.


Il posizionamento di @ResponseBodynon dovrebbe avere importanza ... esaminerò GSON ... ma vorrei comunque che questo JSON funzionasse se possibile.
Jaanus

1

Come menzionato da @atott .

Se hai aggiunto l'ultima versione di Jackson nel tuo pom.xml e con Spring 4.0 o più recente, utilizzando @ResponseBodyil tuo metodo di azione e @RequestMappingconfigurato con produces="application/json;charset=utf-8", tuttavia, hai ancora 406 (Non accettabile), immagino che tu debba provare questo in la configurazione del contesto MVC DispatcherServlet:

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

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

È così che ho finalmente risolto il mio problema.


1

Primavera 4.3.10: ho utilizzato le impostazioni seguenti per risolvere il problema.

Passaggio 1: aggiungi le seguenti dipendenze

    <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>

Passaggio 2: aggiungere quanto segue nella configurazione del contesto DispatcherServlet MVC:

<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>

Dalla primavera 3.2, come per la configurazione predefinita favorPathExtension è impostato come true, per questo motivo se la richiesta uri ha estensioni appropriate come .htmspring darà priorità all'estensione. Nel passaggio 2 avevo aggiunto il bean contentNegotiationManager per sovrascriverlo.


1

Ho avuto lo stesso problema perché mi mancava l'annotazione @EnableWebMvc. (Tutte le mie configurazioni di primavera sono basate su annotazioni, l'equivalente XML sarebbe mvc: annotation-driven)


0

assicurati di avere la versione jackson corretta nel tuo classpath


Ho aggiunto jackson-all-1.8.5.jar alla mia WEB-INF/libcartella, ma sempre lo stesso problema: /
Jaanus

0

Controlla come ha fatto @joyfun per la versione corretta di jackson ma controlla anche le nostre intestazioni ... Accetta / potrebbe non essere trasmesso dal client ... usa firebug o equivalente per controllare cosa sta effettivamente inviando la tua richiesta get. Penso che l'attributo headers dell'annotazione / possa / stia controllando i letterali anche se non ne sono sicuro al 100%.


Ho aggiunto le intestazioni di firebug al post principale. Stanno bene?
Jaanus

0

Oltre agli ovvi problemi ne ho avuto un altro che non ho potuto risolvere indipendentemente dall'inclusione di tutti i possibili JAR, dipendenze e annotazioni nel servlet Spring. Alla fine ho scoperto di avere un'estensione di file sbagliata, intendo dire che avevo due servlet separati in esecuzione nello stesso contenitore e avevo bisogno di mappare su estensioni di file diverse dove una era ".do" e l'altra usata per gli abbonamenti era chiamata casualmente ". sub". Tutto bene ma SUB è un'estensione di file valida normalmente usata per i file dei sottotitoli dei film e quindi Tomcat sovrascriveva l'intestazione e restituiva qualcosa come "text / x-dvd.sub ..." quindi tutto andava bene ma l'applicazione si aspettava JSON ma riceveva i sottotitoli quindi tutto quello che dovevo fare è cambiare la mappatura nel mio web.xmlfile che ho aggiunto:

<mime-mapping>
    <extension>sub</extension>
    <mime-type>application/json</mime-type>
</mime-mapping>

0

Ho avuto lo stesso problema, purtroppo, nessuna soluzione qui ha risolto il mio problema poiché il mio problema era qualcosa in una classe diversa.

Ho prima controllato che tutte le dipendenze siano a posto come suggerito da @bekur, quindi ho controllato la richiesta / risposta che viaggia dai client al server tutte le intestazioni erano a posto e correttamente impostate da Jquery. Ho quindi controllato RequestMappingHandlerAdapter MessageConverterse tutti e 7 erano a posto, ho davvero iniziato a odiare la primavera! Ho quindi aggiornato da Spring 4.0.6.RELEASEa 4.2.0.RELEASEHo ottenuto un'altra risposta piuttosto che quella sopra. EraRequest processing failed; nested exception is java.lang.IllegalArgumentException: No converter found for return value of type

Ecco il mio metodo di controller

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

La soluzione era fare in modo che UploadPictureResult non estendesse WebResponse

Per qualche motivo la primavera non è stata in grado di determinare come convertire UploadPictureReslt quando ha esteso WebResponse


0
<dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.8.0</version>
    </dependency>

non uso l'autenticazione SSL e questo jackson-databind contiene jackson-core.jar e jackson-databind.jar, quindi cambio il contenuto RequestMapping in questo modo:

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

attenzione: se il tuo produce non è di tipo "application / json" e non l'avevo notato e ho ricevuto un errore 406, aiuto questo può aiutarti.


0

controlla questo thread. spring mvc restcontroller return json string p / s: dovresti aggiungere jack son mapping config alla tua classe 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()); }


0

Questa è la risposta dell'aggiornamento per springVersion = 5.0.3.RELEASE.

Quelle risposte di cui sopra verranno elaborate solo con le versioni precedenti di springVersion <4.1 . per l'ultima primavera devi aggiungere le seguenti dipendenze nel file 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

Spero che questo sia utile per chi utilizza l'ultima versione primaverile.


-3

Puoi rimuovere l'elemento header in @RequestMapping e provare ..

Piace


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

Immagino che la primavera esegua un "controllo contiene" anziché una corrispondenza esatta per le intestazioni di accettazione. Tuttavia, vale la pena provare a rimuovere l'elemento intestazioni e controllare.


Ho rimosso, ma ancora errore. A proposito, quando guardo il registro di Tomcat, quindi la query con questo è stato weatherService.getCurrentWeather(id);"attivato" ... quindi qualcosa funziona ... è possibile che appaia 406 e Hibernate SQL select funzioni nello stesso tempo?
Jaanus

Per favore prova questo dovrebbe funzionare. Aggiungi questa annotazione sul controller @RequestMapping (method = RequestMethod.GET, headers = {"Accept = text / xml, application / json"})
sabato
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.