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

85

это мой 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;
}

Spring-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 было два похожих вопроса, я попробовал все принятые подсказки, но они не сработали, я думаю ...

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

Яанус
источник

Ответы:

107

406 неприемлемо

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

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

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

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

  • Джексон-ядро-asl-1.7.4.jar
  • Джексон-маппер-asl-1.7.4.jar
Виллу Сепман
источник
Нет, проблема не в этом, проверьте мой ответ.
Jaanus
Если настройка HttpMessageConverters вручную решила вашу проблему, то использование mvc: с управлением аннотациями будет делать то же самое, что и автоматически настраивает преобразователи и HandlerAdapters (HA). Обратите внимание, что если вы явно настроите любую HA, все остальные настройки по умолчанию будут отменены.
Виллу Сепман,
Хм, что это mvcтам? Я использовал <tx:annotation-driven />и txxmlns:tx="http://www.springframework.org/schema/tx"
Jaanus
1
У вас есть что-то вроде: <?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">а jar-файлы spring-web-3.0.x и spring-webmvc-3.0.x?
Виллу Сепман,
1
Ах, у меня там не было этой схемы .. но спасибо, это помогло мне. Я думал, что tx:annotation-drivenэто то же самое, что mvc:annotation-driveили что-то.
Jaanus
74

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

также убедитесь, что у вас есть следующая банка:

<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, неприемлемо в соответствии с заголовками запроса accept

АКБ
источник
Этот ответ является версией главного ответа для Maven, и он отлично работает! Исключения Maven могут быть более ясными в отношении того, что на самом деле происходит под капотом.
Cotta
4
Можете ли вы указать, где это задокументировано в официальной документации Springs? Как кто-то может знать, что в этом проблема?
Adelin
Вам нужно только указать зависимости для jackson-databind и jackson-mapper-asl, два других являются транзитивными зависимостями и все равно будут разрешены.
anre
1
У меня это сработало только после добавления вторых двух зависимостей. Спасибо.
Док Уотсон,
И то и другое вам точно не понадобится. Spring добавит MappingJacksonHttpMessageConverterдля Jackson 1 и MappingJackson2HttpMessageConverterдля Jackson 2. Каждый из них достаточно хорош для сериализации / десериализации JSON. Вам нужен только один (выберите Jackson 2, так как он более многофункциональный).
Сотириос Делиманолис
16

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

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

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

kdgregory
источник
Спасибо огромное! Я новичок в Spring MVC, и мне было очень трудно понять, как вернуть JSON. Все упоминают отсутствие аннотаций @ResponseBody и зависимости Джексона как причину 406 ошибок. В моем случае оказалось, что мне просто не хватало метода доступа к общедоступному полю, принадлежащему объекту, который я хотел вернуть как JSON.
Энтони Джек,
Спасибо @kdgregory! Я забыл добавить геттер / сеттер для поля. Добавление их устранило эту проблему.
Рубенс Мариуццо
16

У меня была та же проблема, мой метод контроллера выполняется, но ответ - Ошибка 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.

атотт
источник
Привет, atott, у меня такая же проблема, и ваш совет об изменении расширения запроса решил мою проблему. Большое спасибо за то, что поделились своим решением !!
jherranzm
В моем случае это был идентификатор пути отдыха с расширением в нем (в тесте), который вызвал 406 по той же причине, в то время как нормальный контроллер работает (даже если вы должны были использовать расширение в идентификаторе пути отдыха).
Jur_
9

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

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

jackson-core-asl-1.9.X.jar jackson-mapper-asl-1.9.X.jar
Раджу Рати
источник
6

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

Сопоставление спокойных запросов ajax с Spring

Я цитирую:

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

Яанус
источник
3

Проверьте <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

ШИВА
источник
2
<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-base</artifactId>
    <version>2.6.3</version>
</dependency>
Раджан
источник
2
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа.
Франческо Мензани,
2

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

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

Хейзел Трост
источник
Это была моя проблема. Я меняю свои сеттеры с общедоступных на защищенные, и Джексон перестал работать.
JuanMiguel
Та же проблема здесь, я использовал, а AbstractMap.SimpleImmutableEntryзатем понижал до AbstractMap.SimpleEntry, все еще нет кубиков, поскольку у него нет установщика для ключа. Пошел на это.
Роберт Бейн,
2

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

Риад
источник
1

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

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

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

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

НимЧимпский
источник
Размещение @ResponseBodyне должно иметь значения ... Я посмотрю в GSON ... но все же хотелось бы, чтобы этот JSON работал, если это возможно.
Jaanus
1

Как упоминал @atott .

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

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

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

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

Ворон
источник
1

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

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

Кевин Себастьян Фернандес
источник
1

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

Джамбриз
источник
0

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

радость
источник
Я добавил jackson-all-1.8.5.jar в свою WEB-INF/libпапку, но все равно проблема: /
Jaanus
0

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

Дэйв Джи
источник
Я добавил заголовки от firebug в основной пост. Они в порядке?
Jaanus
0

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

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

Сначала я проверил, что все зависимости установлены, как было предложено @bekur, затем я проверил запрос / ответ, который отправляется от клиентов к серверу, все заголовки были на месте и были правильно установлены JQuery. Затем я проверил, RequestMappingHandlerAdapter MessageConvertersи все 7 из них были на месте, я действительно возненавидел Spring! Затем я обновился до Spring, 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.

Аделин
источник
0
<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, помогите, это может вам помочь.

Крабим
источник
0

проверьте эту ветку. 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()); }

Ань Лам
источник
0

Это ответ на обновление для 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

Надеюсь, это будет полезно тем, кто использует последнюю весеннюю версию.

Паранитарана Сараванаперумала
источник
-3

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

подобно


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

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

стратвейн
источник
Я удалил, но все равно ошибка. Кстати, когда я смотрю журнал tomcat, затем запрос с этим был weatherService.getCurrentWeather(id);"активирован" ... так что-то работает ... возможно ли, что появляется 406 и выбор Hibernate SQL работает одновременно?
Jaanus
Пожалуйста, попробуйте этот, он должен работать. Добавьте эту аннотацию в контроллер @RequestMapping (method = RequestMethod.GET, headers = {"Accept = text / xml, application / json"})
сб,