Solicitud de Spring JSON obteniendo 406 (no aceptable)

85

este es mi javascript:

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

este es mi controlador:

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

Recibiendo este error:

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

Encabezados:

Encabezados de respuesta

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

Solicitar encabezados

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

Recibo el error 406, pero la consulta de hibernación funciona mientras tanto. Esto es lo que dice tomcat log, cada vez que cambio la selección en 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=?

¿Cuál podría ser el problema? Había dos preguntas similares en SO antes, probé todas las sugerencias aceptadas allí, pero supongo que no funcionaron ...

¿Alguna sugerencia? Siéntase libre de hacer preguntas...

Jaanus
fuente

Respuestas:

107

406 No aceptable

El recurso identificado por la solicitud solo es capaz de generar entidades de respuesta que tienen características de contenido no aceptables según los encabezados de aceptación enviados en la solicitud.

Por lo tanto, el encabezado de aceptación de su solicitud es application / json y su controlador no puede devolverlo. Esto sucede cuando no se puede encontrar el HTTPMessageConverter correcto para satisfacer el valor de retorno anotado @ResponseBody. HTTPMessageConverter se registra automáticamente cuando usa <mvc:annotation-driven>, dadas ciertas bibliotecas de 3-d en la ruta de clase.

O no tiene la biblioteca Jackson correcta en su ruta de clases o no ha usado la <mvc:annotation-driven>directiva.

Repliqué con éxito su escenario y funcionó bien usando estas dos bibliotecas y sin headers="Accept=*/*"directiva.

  • jackson-core-asl-1.7.4.jar
  • jackson-mapper-asl-1.7.4.jar
Villu Sepman
fuente
No, ese no fue el problema, revisa mi respuesta.
Jaanus
Si configurar HttpMessageConverters manualmente resolvió su problema, entonces usar mvc: annotation-drive haría lo mismo que configura los convertidores y HandlerAdapters (HA) automáticamente. Tenga en cuenta que si configura cualquier HA explícitamente, cancelará todos los demás valores predeterminados.
Villu Sepman
Hmm, ¿qué es eso mvcahí? Solía <tx:annotation-driven />y TX esxmlns:tx="http://www.springframework.org/schema/tx"
Jaanus
1
¿Tienes algo como: <?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">y jarras spring-web-3.0.xy spring-webmvc-3.0.x?
Villu Sepman
1
Ah, no tenía ese esquema de ubicación allí ... pero gracias, esto me ayudó. Pensé que tx:annotation-drivenera igual mvc:annotation-driveo poco.
Jaanus
74

Tuve el mismo problema, con Latest Spring 4.1.1 en adelante, debe agregar los siguientes frascos 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>

también asegúrese de tener el siguiente jar:

<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, no aceptable de acuerdo con la solicitud "aceptar" encabezados

AKB
fuente
Esta respuesta es la versión compatible con Maven de la respuesta principal, ¡y funciona perfectamente! Las excepciones de Maven podrían ser más claras sobre lo que realmente está sucediendo debajo del capó.
Cotta
4
¿Puede proporcionar dónde está documentado esto en la documentación oficial de Springs? ¿Cómo puede alguien saber que este es el problema?
Adelin
Solo necesita especificar las dependencias de jackson-databind y jackson-mapper-asl, las otras dos son dependencias transitivas y se resolverán de todos modos.
2015
1
Esto solo funcionó para mí después de agregar las dos segundas dependencias. Gracias.
DocWatson
Definitivamente no necesitas ambos. Spring agregará MappingJacksonHttpMessageConverterpara Jackson 1 y MappingJackson2HttpMessageConverterpara Jackson 2. Cada uno de estos es lo suficientemente bueno para serializar / deserializar JSON. Solo necesita uno (elija Jackson 2, ya que tiene más funciones).
Sotirios Delimanolis
16

Hay otro caso en el que se devolverá este estado: si el mapeador de Jackson no puede averiguar cómo serializar su bean. Por ejemplo, si tiene dos métodos de acceso para la misma propiedad booleana isFoo()y getFoo().

Lo que pasa es que la primavera de MappingJackson2HttpMessageConverter llama de Jackson StdSerializerProvider para ver si puede convertir su objeto. En la parte inferior de la cadena de llamadas, StdSerializerProvider._createAndCacheUntypedSerializerlanza un JsonMappingExceptioncon un mensaje informativo. Sin embargo, esta excepción es absorbida StdSerializerProvider._createAndCacheUntypedSerializer, lo que le dice a Spring que no puede convertir el objeto. Al haberse quedado sin convertidores, Spring informa que no se le ha asignado un Acceptencabezado que pueda usar, lo que, por supuesto, es falso cuando lo está dando */*.

Hay un error para este comportamiento, pero se cerró como "no se puede reproducir": el método que se está llamando no declara que puede lanzar, por lo que tragar excepciones es aparentemente una solución apropiada (sí, eso fue sarcasmo). Desafortunadamente, Jackson no tiene ningún registro ... y hay muchos comentarios en la base de código que desearían que lo hiciera, así que sospecho que este no es el único problema oculto.

kdgregory
fuente
Muchas gracias! Soy nuevo en Spring MVC y me costaba mucho averiguar cómo devolver JSON. Todos mencionan las anotaciones @ResponseBody que faltan y las dependencias de Jackson como la causa de los errores 406. En mi caso, resulta que solo me faltaba un método de acceso para un campo público que pertenecía al objeto que quería devolver como JSON.
Anthony Jack
¡Gracias @kdgregory! Olvidé agregar getter / setter para un campo. Agregarlos solucionó este problema.
Rubens Mariuzzo
16

Tuve el mismo problema, mi método de controlador se ejecuta pero la respuesta es el Error 406. Depuraré AbstractMessageConverterMethodProcessor#writeWithMessageConvertersy encontré que el método ContentNegotiationManager#resolveMediaTypessiempre devuelve lo text/htmlque no es compatible con MappingJacksonHttpMessageConverter. El problema es que org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategyfunciona antes org.springframework.web.accept.HeaderContentNegotiationStrategyy la extensión de mi solicitud /get-clients.htmles la causa de mi problema con el Error 406. Acabo de cambiar la URL de la solicitud a /get-clients.

atott
fuente
Hola atott, tengo el mismo problema y tu consejo sobre el cambio de la extensión de la solicitud resolvió mi problema. ¡¡Muchas gracias por compartir tu solución !!
jherranzm
En mi caso, fue un ID de ruta de descanso con una extensión en él (en la prueba) lo que causó el 406 por la misma razón, mientras que el controlador normal funciona (incluso si tuviera que usar una extensión en el ID de ruta de descanso).
Jur_
9

Asegúrese de que los siguientes 2 jarestén presentes en la ruta de clases.

Si falta alguno o ambos, entonces aparecerá este error.

jackson-core-asl-1.9.X.jar jackson-mapper-asl-1.9.X.jar
Raju Rathi
fuente
6

Finalmente encontré la respuesta desde aquí:

Asignación de solicitudes de descanso ajax a spring

Yo cito:

Las anotaciones @ RequestBody / @ ResponseBody no usan resolutores de vista normales, usan sus propios HttpMessageConverters. Para usar estas anotaciones, debe configurar estos convertidores en AnnotationMethodHandlerAdapter, como se describe en la referencia (probablemente necesite MappingJacksonHttpMessageConverter).

Jaanus
fuente
3

Verifique <mvc:annotation-driven />dispatcherservlet.xml, si no, agréguelo. Y añadir

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

estas dependencias en su pom.xml

SHIVA
fuente
2
<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-base</artifactId>
    <version>2.6.3</version>
</dependency>
Rajan
fuente
2
Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre cómo y / o por qué resuelve el problema mejoraría el valor de la respuesta a largo plazo.
Francesco Menzani
2

Probablemente nadie se esté desplazando hacia abajo hasta ahora, pero ninguna de las soluciones anteriores me lo solucionó, pero todos mis métodos getter publicsí lo hicieron.

Dejé mi visibilidad de getter en package-private; Jackson decidió que no podía encontrarlos y explotó. (Utilizándolo @JsonAutoDetect(getterVisibility=NON_PRIVATE)solo parcialmente lo arregló.

Hazel Troost
fuente
Ese era exactamente mi problema. Cambié mis armadores de público a protegido y Jackson dejó de funcionar.
JuanMiguel
El mismo problema aquí, estaba usando y AbstractMap.SimpleImmutableEntryluego degradado a AbstractMap.SimpleEntry, todavía sin dados, ya que no tiene un colocador para la clave. Se ha ido pojo en esto.
Robert Bain
2

Asegúrese de que el objeto enviado (Weather en este caso) contenga getter / setter

Riadh
fuente
1

En el controlador, ¿no debería la anotación del cuerpo de la respuesta estar en el tipo de retorno y no en el método, así:

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

También usaría la función jquery.ajax sin procesar y me aseguraría de que contentType y dataType se estén configurando correctamente.

En una nota diferente, encuentro el manejo de primavera de json bastante problemático. Fue más fácil cuando lo hice todo yo mismo usando cuerdas y GSON.

NimChimpsky
fuente
La ubicación de @ResponseBodyno debería importar ... Buscaré en GSON ... pero aún así me gustaría que este JSON funcionara si es posible.
Jaanus
1

Como mencionó @atott .

Si ha agregado la última versión de Jackson en su pom.xml, y con Spring 4.0 o más reciente, usando @ResponseBodysu método de acción y @RequestMappingconfigurado con produces="application/json;charset=utf-8", sin embargo, todavía tiene 406 (No aceptable), supongo que debe probar esto en su configuración de contexto MVC DispatcherServlet:

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

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

Así es como finalmente resolví mi problema.

Cuervo
fuente
1

Spring 4.3.10: utilicé la siguiente configuración para resolver el problema.

Paso 1: agregue las siguientes dependencias

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

Paso 2: agregue lo siguiente en la configuración de contexto de 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>

Desde la primavera 3.2, según la configuración predeterminada, favorPathExtension se establece como verdadero, debido a esto, si la solicitud uri tiene las extensiones adecuadas, como .htmprimavera, dará prioridad a la extensión. En el paso 2, agregué el bean contentNegotiationManager para anular esto.

Kevin Sebastián Fernández
fuente
1

Tenía el mismo problema porque me faltaba la anotación @EnableWebMvc. (Todas mis configuraciones de primavera están basadas en anotaciones, el equivalente XML sería mvc: controlado por anotaciones)

jambriz
fuente
0

asegúrese de tener la versión correcta de Jackson en su classpath

alegría
fuente
Agregué jackson-all-1.8.5.jar a mi WEB-INF/libcarpeta, pero sigue siendo el mismo problema: /
Jaanus
0

Verifique, como hizo @joyfun, la versión correcta de jackson, pero también verifique nuestros encabezados ... Aceptar / puede que no sea transmitido por el cliente ... use firebug o equivalente para verificar qué está enviando realmente su solicitud de obtención. Creo que el atributo de encabezados de la anotación / puede / estar verificando literales, aunque no estoy 100% seguro.

Dave G
fuente
Agregué los encabezados de firebug a la publicación principal. Estan bien
Jaanus
0

Aparte de los problemas obvios, tuve otro que no pude solucionar independientemente de incluir todos los JAR, dependencias y anotaciones posibles en el servlet Spring. Finalmente descubrí que tengo una extensión de archivo incorrecta, quiero decir que tenía dos servlet separados ejecutándose en el mismo contenedor y necesitaba asignar diferentes extensiones de archivo donde una era ".do" y la otra, como se usa para las suscripciones, tenía un nombre aleatorio ". sub". Todo bien, pero SUB es una extensión de archivo válida que normalmente se usa para archivos de subtítulos de películas y, por lo tanto, Tomcat anulaba el encabezado y devolvía algo como "texto / x-dvd.sub ...", así que todo estaba bien, pero la aplicación esperaba JSON pero obtenía subtítulos. por lo tanto, todo lo que tuve que hacer es cambiar la asignación en mi web.xmlarchivo que agregué:

<mime-mapping>
    <extension>sub</extension>
    <mime-type>application/json</mime-type>
</mime-mapping>
Alex Rashkov
fuente
0

Tuve el mismo problema, desafortunadamente, ninguna de las soluciones aquí resolvió mi problema, ya que mi problema era algo de una clase diferente.

Primero verifiqué que todas las dependencias estén en su lugar como lo sugiere @bekur, luego verifiqué que la solicitud / respuesta que viaja de los clientes al servidor, todos los encabezados estaban en su lugar y configurados correctamente por Jquery. Luego revisé el RequestMappingHandlerAdapter MessageConvertersy los 7 estaban en su lugar, ¡realmente comencé a odiar Spring! Luego actualicé desde Spring 4.0.6.RELEASEhasta 4.2.0.RELEASEque obtuve otra respuesta en lugar de la anterior. EraRequest processing failed; nested exception is java.lang.IllegalArgumentException: No converter found for return value of type

Aquí está mi método de controlador

  @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 solución fue hacer que UploadPictureResult no extendiera WebResponse

Por alguna razón, Spring no pudo determinar cómo convertir UploadPictureReslt cuando extendió WebResponse

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

No uso la autenticación SSL y este jackson-databind contiene jackson-core.jar y jackson-databind.jar, y luego cambio el contenido de RequestMapping de esta manera:

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

atención: si su producción no es del tipo "application / json" y no me di cuenta de esto y obtuve un error 406, ayuda, esto puede ayudarlo.

Cangrejo
fuente
0

revisa este hilo. spring mvc restcontroller return json string p / s: debe agregar la configuración de mapeo de jack son a su clase 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
fuente
0

Esta es la respuesta de actualización para springVersion = 5.0.3.RELEASE.

Las respuestas anteriores solo se trabajarán con versiones anteriores de springVersion <4.1 . para la última primavera, debe agregar las siguientes dependencias en el archivo 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

Espero que esto sea útil para quienes usan la última versión de primavera.

Paraneetharan Saravanaperumal
fuente
-3

¿Puedes eliminar el elemento de encabezados en @RequestMapping e intentar ...

Me gusta


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

Supongo que Spring hace una 'verificación de contenido' en lugar de una coincidencia exacta para aceptar encabezados. Pero aún así, vale la pena intentar eliminar el elemento de encabezados y verificar.

stratwine
fuente
Eliminé, pero aún error. Por cierto, cuando miro el registro de tomcat, la consulta con esto se weatherService.getCurrentWeather(id);"activó" ... así que algo funciona ... ¿es posible que aparezca 406 y la selección de Hibernate SQL funcione al mismo tiempo?
Jaanus
Por favor, pruebe este, debería funcionar. Agregue esta anotación en el controlador @RequestMapping (método = RequestMethod.GET, headers = {"Accept = text / xml, application / json"})
sábado