POST JSON виходить з ладу з 415 носіями, що не підтримуються, Spring 3 mvc


171

Я намагаюся надіслати запит на пошту сервлету. Запит надсилається через jQuery таким чином:

var productCategory = new Object();
productCategory.idProductCategory = 1;
productCategory.description = "Descrizione2";
newCategory(productCategory);

де новаКатегорія

function newCategory(productCategory)
{
  $.postJSON("ajax/newproductcategory", productCategory, function(
      idProductCategory)
  {
    console.debug("Inserted: " + idProductCategory);
  });
}

і postJSON є

$.postJSON = function(url, data, callback) {
    return jQuery.ajax({
    'type': 'POST',
    'url': url,
    'contentType': 'application/json',
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
    });
};

З firebug я бачу, що JSON надсилається правильно:

{"idProductCategory":1,"description":"Descrizione2"}

Але я отримую 415 непідтримуваний тип медіа. Весняний контролер mvc має підпис

    @RequestMapping(value = "/ajax/newproductcategory", method = RequestMethod.POST)
public @ResponseBody
Integer newProductCategory(HttpServletRequest request,
        @RequestBody ProductCategory productCategory)

Деякі дні тому це працювало, зараз це не так. Я покажу більше коду, якщо потрібно. Дякую


Що ви змінили за кілька днів тому? Крім того, не var productCategory = { idProductCategory: 1, description: "Descrizione2" };буде більш стислим і легким для читання? Чи потрібно сказати Весні, щоб прийняти application/jsonконкретно? Іншими словами, чи очікується, що дані прийдуть у формі?
Дейв Ньютон

Багато речей, оскільки я працював над іншою частиною цього проекту, і сьогодні знайшов цей регрес. У цій частині я нічого не змінив. Так, я повинен використовувати цей спосіб, тому що я отримую інформацію від форми.
gc5

Ні, ви ні, ви отримуєте це з посади JSON Ajax, яка не є такою ж, як кодовані формою дані.
Дейв Ньютон

1
Ви впевнені, що Джексон все ще доступний у вашому CLASSPATH?
Томаш Нуркевич

1
якщо ти надсилаєш текст / json замість програми / json, ти отримуєш ту саму помилку
Blacksonic

Відповіді:


249

У мене це було раніше з Spring @ResponseBody, і це було тому, що не було прийнято заголовка прийняття із запитом. Прийняти заголовок може бути болем встановити за допомогою jQuery, але це працювало для мене джерелом

$.postJSON = function(url, data, callback) {
    return jQuery.ajax({
    headers: { 
        'Accept': 'application/json',
        'Content-Type': 'application/json' 
    },
    'type': 'POST',
    'url': url,
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
    });
};

Заголовок Content-Type використовується @RequestBody для визначення формату даних, що надсилаються від клієнта у запиті. Заголовок прийняття використовується @ResponseBody, щоб визначити, у якому форматі відправити дані клієнту у відповідь. Ось чому вам потрібні обидва заголовки.


1
заголовки: {...} і JSON.stringify (...) завжди відключають мене.
Тім Перрі

1
Не маю ідеї, чому це не більш задокументовано. Ця проблема змусила мене витрачати стільки часу. Велике спасибі!
Хьюго Нава Копп

Я очікував, що Spring за замовчуванням підтримує дані форми форми, але це не так. Тож дякую за (зараз досить давнє) рішення.
RiZKiT

Я використовував листоношу, щоб зробити запит на
поставку

21

додавання типу вмісту до запиту, коли application/jsonвирішено проблему


18

У мене була подібна проблема, але я виявив, що я нехтував наданням конструктора за замовчуванням для DTO, який був анотований з @RequestBody.


те саме сталося і зі мною. У мене було 2 методи з такою ж назвою і отримували 415. Дякую!
Даніель Вілас-Боас

12

Я вважаю, що я зіткнувся саме з тим же питанням. Після незліченних годин боротьби з JSON, JavaScript та сервером, я виявив винуватця: у моєму випадку я мав об’єкт Date в DTO, цей об'єкт Date був перетворений у String, щоб ми могли показати його у поданні з формат: HH: мм.

Коли інформація JSON була відправлена ​​назад, цей об'єкт String Date повинен був бути перетворений назад у повний об'єкт Date, тому нам також потрібен метод, щоб встановити його в DTO. Велике АЛЕ - у вас не може бути двох методів з тим самим іменем (Перевантаження) у DTO, навіть якщо вони мають різний тип параметрів (String vs Date), оскільки це призведе до помилки типу 415 непідтримуваних носіїв.

Це був мій метод контролера

  @RequestMapping(value = "/alarmdownload/update", produces = "application/json", method = RequestMethod.POST)
  public @ResponseBody
  StatusResponse update(@RequestBody AlarmDownloadDTO[] rowList) {
    System.out.println("hola");
    return new StatusResponse();
  }

Це був мій приклад DTO (ідентифікатори get / set та preAlarm get metode не включаються для короткості коду):

@JsonIgnoreProperties(ignoreUnknown = true)
public class AlarmDownloadDTO implements Serializable {

  private static final SimpleDateFormat formatHHmm = new SimpleDateFormat("HH:mm");

  private String id;
  private Date preAlarm;

  public void setPreAlarm(Date date) { 
    this.preAlarm == date;
  }
  public void setPreAlarm(String date) {    
    try {
      this.preAlarm = formatHHmm.parse(date);
    } catch (ParseException e) {
      this.preAlarm = null;
    } catch (NullPointerException e){
      this.preAlarm = null;
    }
  }
}

Щоб все працювало, потрібно видалити метод з параметром Тип дати. Ця помилка дуже засмучує. Сподіваюся, це може врятувати когось години налагодження.


Дякую - або ви можете просто перейменувати один із сетерів. У мене були обидва public void setParameters(List<Parameter> parameters)& public void setParameters(Parameter... parameters)методи в квасолі, змінивши останній, щоб addParametersвирішити проблему для мене.
Conor Svensson

Хіба не проблема в тому, що тіло це.preAlarm == дата, а не this.preAlarm = дата?
Майкл відновить Моніку Селліо

12

Я зіткнувся з подібною проблемою, і ось як це я вирішив,

Проблема пов’язана з процесом перетворення з JSON в Java, для правильного перетворення потрібні правильні бібліотеки Джексона часу.

Додайте наступні банки (через залежність або завантажуючи та додаючи на класний шлях).

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

Це має вирішити проблему.

Повний код:

function() {
  $.ajax({
    type: "POST",
    url: "saveUserDetails.do",
    data: JSON.stringify({
      name: "Gerry",
      ity: "Sydney"
    }),
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    success: function(data) {
      if (data.status == 'OK')
        alert('Person has been added');
      else
        alert('Failed adding person: ' + data.status + ', ' + data.errorMessage);
}

і підпис контролера виглядає приблизно так:

@RequestMapping(value = "/saveUserDetails.do", method = RequestMethod.POST)
public @ResponseBody Person addPerson( @RequestBody final  Person person) {

Сподіваюся, це допомагає


Тільки jackson-databindпотрібно.
Alex78191

8

Я зіткнувся з цим питанням, коли інтегрував весняний завантажувач із весняним mvc. Я вирішив це, просто додавши ці залежності.

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

5

Невелика бічна примітка - натрапила на цю ж помилку під час розробки веб-додатку. Ми виявили помилку, граючи в сервісі з Firefox Poster, в тому, що і поля, і значення в Json повинні бути оточені подвійними лапками. Наприклад..

[ {"idProductCategory" : "1" , "description":"Descrizione1"}, 
  {"idProductCategory" : "2" , "description":"Descrizione2"} ]

У нашому випадку ми заповнили json через javascript, що може бути трохи заплутано, коли справа стосується одинарних / подвійних лапок, з того, що я чув.

Те, що було сказано раніше в цій та інших публікаціях, зокрема, заголовки "Прийняти" та "Тип вмісту", також застосовується.

Сподіваюсь, що допоможе.


3

Мені вдалося зрозуміти, як це зробити. Скажіть мені, якщо я помиляюся. Я використовував лише один спосіб серіалізації / десеріалізації: я видалив усі примітки щодо цього ( @JSONSerializeта @JSONDeserialize) та зареєстрував серіалізатори та десеріалізатори в CustomObjectMapperкласі. Я не знайшов статті, яка пояснювала б таку поведінку, але вирішила таким чином. Сподіваюся, що це корисно.


Зі мною трапляється те саме! Будь-яке пояснення, чому це відбувається?
Примхливий

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

1

У мене була така ж проблема. Мені довелося виконати наступні кроки, щоб вирішити проблему:

1. Переконайтеся, що у вас є такі залежності:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson-version}</version> // 2.4.3
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson-version}</version> // 2.4.3
    </dependency>

2. Створіть такий фільтр:

    public class CORSFilter extends OncePerRequestFilter {

        @Override
        protected void doFilterInternal(HttpServletRequest request,
                                        HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {

            String origin = request.getHeader("origin");
            origin = (origin == null || origin.equals("")) ? "null" : origin;
            response.addHeader("Access-Control-Allow-Origin", origin);
            response.addHeader("Access-Control-Allow-Methods", "POST, GET, PUT, UPDATE, DELETE, OPTIONS");
            response.addHeader("Access-Control-Allow-Credentials", "true");
            response.addHeader("Access-Control-Allow-Headers",
                    "Authorization, origin, content-type, accept, x-requested-with");

            filterChain.doFilter(request, response);
        }
    }

3. Застосуйте вищевказаний фільтр для запитів у web.xml

    <filter>
        <filter-name>corsFilter</filter-name>
        <filter-class>com.your.package.CORSFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>corsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Сподіваюся, це комусь корисно.


jackson-coreє залежність від jackson-databind, так що немає необхідності додавати його безпосередньо.
Alex78191

1
Чому потрібно додати фільтр CORS?
Alex78191

1

Весняний черевик + весна mvn

з випуском

@PostMapping("/addDonation")
public String addDonation(@RequestBody DonatorDTO donatorDTO) {

з розчином

@RequestMapping(value = "/addDonation", method = RequestMethod.POST)
@ResponseBody
public GenericResponse addDonation(final DonatorDTO donatorDTO, final HttpServletRequest request){

0

Я вирішив цю проблему, додавши прив'язку даних jackson-json до моєї пом.

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

0

У свій Клас моделі додайте анотацію про властивість json, також мати конструктор за замовчуванням

@JsonProperty("user_name")
private String userName;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;

0

У мене було те саме питання. додавання

<mvc:annotation-driven />
<mvc:default-servlet-handler />

до весни-xml вирішив це


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.