Spring JSON-запрос на получение 406 (не приемлемо)

Это мой JavaScript:

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

это мой контроллер:

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

весна-servlet.xml

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

Получение этой ошибки:

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

Заголовки:

Заголовки ответа

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

Заголовки запроса

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

Интересная заметка:

Я получаю ошибку 406, но запрос гибернации пока что работает. Вот что говорит журнал tomcat каждый раз, когда я меняю выбор в 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=?

В чем может быть проблема? Ранее в SO было два похожих вопроса, я попробовал все принятые намеки, но они не сработали, я думаю...

Какие-либо предложения? Не стесняйтесь задавать вопросы...

26 ответов

Решение

406 Недопустимо

Ресурс, идентифицированный запросом, способен генерировать только объекты ответа, которые имеют характеристики контента, неприемлемые в соответствии с заголовками принятия, отправленными в запросе.

Итак, ваш заголовок подтверждения запроса - application/json, и ваш контроллер не может его вернуть. Это происходит, когда не удается найти правильный HTTPMessageConverter, удовлетворяющий аннотированному возвращаемому значению @ResponseBody. HTTPMessageConverter автоматически регистрируются при использовании <mvc:annotation-driven>, учитывая определенные сторонние библиотеки в classpath.

Либо у вас нет правильной библиотеки Джексона в вашем пути к классам, либо вы не использовали <mvc:annotation-driven> директивы.

Я успешно воспроизвел ваш сценарий, и он работал нормально, используя эти две библиотеки, и нет headers="Accept=*/*" директивы.

  • ДЖЕКСОН-ядро-ASL-1.7.4.jar
  • ДЖЕКСОН-картограф-ASL-1.7.4.jar

У меня была та же проблема, с последней весной 4.1.1 и выше, вам нужно добавить следующие файлы jar в 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>

также убедитесь, что у вас есть следующий 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, не принимается согласно запросу "принять" заголовки

В другом случае этот статус будет возвращен: если картограф Джексона не может понять, как сериализовать ваш компонент. Например, если у вас есть два метода доступа для одного и того же логического свойства, isFoo() а также getFoo(),

Происходит то, что Spring MappingJackson2HttpMessageConverter вызывает StdSerializerProvider Джексона, чтобы посмотреть, сможет ли он преобразовать ваш объект. В нижней части цепочки вызовов StdSerializerProvider._createAndCacheUntypedSerializer бросает JsonMappingException с информативным сообщением. Однако это исключение поглощено StdSerializerProvider._createAndCacheUntypedSerializer, который сообщает Spring, что он не может конвертировать объект. Spring исчерпал конвертеры и сообщает, что Accept заголовок, который он может использовать, что, конечно, является поддельным, когда вы даете ему */*,

В этом поведении есть ошибка, но она была закрыта как "не может воспроизвести": вызываемый метод не объявляет, что он может выдавать, поэтому проглатывание исключений, очевидно, является подходящим решением (да, это был сарказм). К сожалению, у Джексона нет никакой регистрации... и в кодовой базе есть много комментариев, желающих это сделать, поэтому я подозреваю, что это не единственная скрытая ошибка.

У меня была та же проблема, мой метод контроллера выполняется, но ответ - Ошибка 406. Я отлаживаю AbstractMessageConverterMethodProcessor#writeWithMessageConverters и нашел этот метод ContentNegotiationManager#resolveMediaTypes всегда возвращается text/html который не поддерживается MappingJacksonHttpMessageConverter, Проблема в том, что org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy работает раньше, чем org.springframework.web.accept.HeaderContentNegotiationStrategyи продление моего запроса /get-clients.html является причиной моей проблемы с ошибкой 406. Я просто изменил URL-адрес запроса на /get-clients,

Убедитесь, что отправленный объект (в данном случае Weather) содержит getter/setter

Убедитесь, что следующие 2 jarприсутствуют в пути к классам.

Если какой-либо один или оба отсутствуют, то эта ошибка придет.

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

Наконец-то нашел ответ отсюда:

Картирование успокоительных запросов Ajax к весне

Я цитирую:

@ RequestBody / @ ResponseBody аннотации не используют обычные преобразователи представления, они используют свои собственные HttpMessageConverters. Чтобы использовать эти аннотации, вы должны сконфигурировать эти конвертеры в AnnotationMethodHandlerAdapter, как описано в ссылке (вам, вероятно, понадобится MappingJacksonHttpMessageConverter).

Проверьте <mvc:annotation-driven /> в dispatcherservlet.xml, если не добавить его. И добавить

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

эти зависимости в вашем pom.xml

Вероятно, никто не прокручивает эту страницу так далеко, но ни одно из вышеперечисленных решений не исправило это для меня, но сделал все мои методы получения public сделал.

Я оставил свой видимость получателя в пакете-частном; Джексон решил, что не может их найти, и взорвался. (С помощью @JsonAutoDetect(getterVisibility=NON_PRIVATE) только частично исправил это.

У меня возникла та же проблема, потому что мне не хватало аннотации @EnableMvc. (Вся моя весенняя конфигурация основана на аннотациях, XML-эквивалент будет mvc: на основе аннотаций)

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

В контроллере не должна быть аннотация тела ответа на тип возвращаемого значения, а не на метод, например так:

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

Я также использовал бы функцию raw jquery.ajax и убедился, что contentType и dataType установлены правильно.

С другой стороны, пружинная обработка json довольно проблематична. Было проще, когда я делал все сам, используя строки и GSON.

Как уже упоминалось@atott.

Если вы добавили последнюю версию Jackson в ваш файл pom.xml и в Spring 4.0 или новее, используйте @ResponseBody на ваш метод действий и @RequestMapping настроен с produces="application/json;charset=utf-8"Тем не менее, у вас все еще есть 406(не приемлемо), я думаю, вам нужно попробовать это в вашей конфигурации контекста MVC DispatcherServlet:

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

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

Так я наконец решил свою проблему.

Проверьте эту тему. spring mvc restcontroller возвращает строку json p/s: вы должны добавить конфигурацию сопоставления jack son в ваш класс 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()); }

Весна 4.3.10: я использовал приведенные ниже настройки для решения проблемы.

Шаг 1: Добавьте следующие зависимости

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

Шаг 2. Добавьте нижеприведенное в свою конфигурацию контекста 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>

Начиная с весны 3.2, в соответствии с конфигурацией по умолчанию значение favPathExtension установлено в значение true, из-за этого, если в запросе есть какие-либо надлежащие расширения, такие как .htm весна будет отдавать приоритет расширению. На шаге 2 я добавил bean-компонент contentNegotiationManager, чтобы переопределить это.

Для людей, которые все еще сталкиваются с ошибкой 406 после добавления ':*' к регулярному выражению переменной пути.

Переопределить приведенный ниже метод интерфейса WebMvcConfigurer в любом классе @Configuration.

      @Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(true)
            .mediaType("json", MediaType.APPLICATION_JSON)
            .mediaType("xml", MediaType.APPLICATION_XML)
            .mediaType("com", MediaType.APPLICATION_JSON);
}

Я добавил «com» ​​в качестве расширения, поскольку мы использовали идентификаторы электронной почты в качестве переменной пути и ожидали ответа application/json от нашего приложения.

Это помогает мне решить проблему.

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

Однако обратите внимание, что это не включает конкретную конфигурацию, которая была у вас в исходном фрагменте для согласования контента. Итак, если вы включите только<mvc:annotation-driven />и опуститьcontentNegotiationManagerbean-компонента, приложение будет использовать поведение по умолчанию для согласования содержимого. Поведение по умолчанию обычно включает в себя рассмотрениеAcceptзаголовок и, если доступно, расширение файла в URL-адресе, чтобы определить тип носителя ответа.

Убедитесь, что у вас есть правильная версия Джексона в вашем classpath

Это обновленный ответ для springVersion=5.0.3.RELEASE.

Эти ответы выше будут работать только в более старой версии SpringVersion <4.1. для последней весны вы должны добавить следующие зависимости в файл 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

Я надеюсь, что это будет полезно для тех, кто использует последнюю весеннюю версию.

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

я не использую аутентификацию ssl, и этот jackson-databind содержит jackson-core.jar и jackson-databind.jar, а затем изменяю содержимое RequestMapping следующим образом:

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

внимание: если ваш продукт не относится к типу "application/json", и я не заметил этого и получил ошибку 406, помогите вам.

Проверьте, как @joyfun сделал для правильной версии Джексона, но также проверьте наши заголовки... Принять / не может быть передан клиентом... используйте firebug или эквивалентный, чтобы проверить, что на самом деле отправляет ваш запрос на получение. Я думаю, что атрибут заголовков аннотации / может / проверяет литералы, хотя я не уверен на 100%.

Кроме очевидных проблем, у меня была еще одна, которую я не мог исправить независимо от включения всех возможных JAR-файлов, зависимостей и аннотаций в сервлете Spring. В конце концов я обнаружил, что у меня неправильное расширение файла, потому что я имею в виду, что у меня два отдельных сервлета работают в одном и том же контейнере, и мне нужно было сопоставить с различными расширениями файлов, где одно было ".do", а другое использовалось для подписок с произвольным именем ". к югу". Все хорошо, но SUB является допустимым расширением файла, обычно используемым для файлов субтитров фильмов, и, таким образом, Tomcat переопределял заголовок и возвращал что-то вроде "text/x-dvd.sub...", так что все было в порядке, но приложение ожидало JSON, но получало субтитры. Таким образом, все, что мне нужно было сделать, это изменить отображение в моем web.xml файл, который я добавил:

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

У меня была та же проблема, к сожалению, ни одно из предложенных здесь решений не решило мою проблему, так как моя проблема была в другом классе.

Сначала я проверил, что все зависимости на месте, как предложено @bekur, затем я проверил запрос / ответ, который передается от клиентов к серверу, все заголовки были правильно установлены Jquery. Затем я проверил RequestMappingHandlerAdapterMessageConverters и все 7 из них были на месте, я действительно начал ненавидеть весну! Я потом обновился от весны 4.0.6.RELEASE в 4.2.0.RELEASE У меня есть другой ответ, а не выше. это было Request processing failed; nested exception is java.lang.IllegalArgumentException: No converter found for return value of type

Вот мой метод контроллера

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

Решением было сделать UploadPictureResult, чтобы не расширять WebResponse

По какой-то причине Spring не смог определить, как конвертировать UploadPictureReslt при расширении WebResponse.

Простой ответ: просто добавьте метод Getter в класс вашего домена/модели.

Но почему это работает??

Под капотом Spring использовал HttpMessageConverters для преобразования вашего входного JSON в объект Java.
Заголовок Accept , который передается в запросе, используется для выбора соответствующего MessageConvertor во время выполнения. Эти преобразователи сообщений используют геттер вашего класса домена/модели для преобразования, поэтому, если нет метода геттера, Marshall и unmarshall Java Objects в JSON и из него не произойдет, даже если вы добавите Jackson в свой путь к классам, потому что даже Jackson lib использует Getter методы сортировки материалов !!.

при весенней загрузке: представьте, что мы хотим вернуть метод веб-сервиса так же, как:

      ResponseEntity.status(HttpStatus.CREATED)
                    .body(myObject);
myObject class **need to** use @Data annotation from lombok pakage

@Data
public class myClass{
...
}

Можете ли вы удалить элемент заголовков в @RequestMapping и попробовать..

подобно


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

Я предполагаю, что spring выполняет проверку содержимого, а не точное совпадение для заголовков accept. Но все же стоит попробовать удалить элемент заголовков и проверить.

Другие вопросы по тегам