Ошибка POST JSON с 415 неподдерживаемым типом носителя, Spring 3 mvc

171

Я пытаюсь отправить запрос POST сервлету. Запрос отправляется через 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 неподдерживаемый тип носителя. Spring mvc контроллер имеет подпись

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

Несколько дней назад это работало, сейчас нет. Я покажу больше кода, если это необходимо. Спасибо

GC5
источник
Что вы изменили с тех пор несколько дней назад? Кроме того, не var productCategory = { idProductCategory: 1, description: "Descrizione2" };будет более кратким и легким для чтения? Вы должны сказать Spring, чтобы принять application/jsonконкретно? Другими словами, это ожидает, что данные придут в форме?
Дэйв Ньютон,
Многое с тех пор, как я работал над другой частью этого проекта, и сегодня я обнаружил этот регресс. В этой части я ничего не менял. Да, я должен использовать этот способ, потому что я получаю информацию из формы.
gc5
Нет, это не так, вы получаете его из сообщения JSON Ajax, которое отличается от данных, закодированных в форме.
Дейв Ньютон,
1
Вы уверены, что Джексон все еще доступен на вашем CLASSPATH?
Томаш Нуркевич
1
если вы отправляете текст / JSON вместо приложения / JSON, вы получаете ту же ошибку
Blacksonic

Ответы:

250

Я имел это раньше с Spring @ResponseBody, и это было потому, что не было отправлено заголовка accept с запросом. Заголовок Accept может быть неудобно устанавливать с помощью 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 для определения формата данных, отправляемых клиентом в запросе. Заголовок accept используется @ResponseBody, чтобы определить, в каком формате отправлять данные обратно клиенту в ответе. Вот почему вам нужны оба заголовка.

Теон
источник
1
заголовки: {...} и JSON.stringify (...) всегда сбивают меня с толку.
Тим Перри
1
Не знаю, почему это не более задокументировано. Эта проблема заставила меня тратить столько времени. Большое спасибо!
Хьюго Нава Копп
Я ожидал, что Spring по умолчанию поддерживает данные формы, но это не так. Итак, спасибо за (теперь довольно старое) решение.
RiZKiT
Я использовал почтальона, чтобы сделать запрос пут, только добавил тип контента: '' application / json ". Спасибо
Джанатбек Шаршеев
21

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

uiroshan
источник
18

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

Джон Шепард
источник
1
Со мной случилось то же самое. У меня было 2 метода с тем же именем, и я получил 415. Спасибо!
Даниэль Вилас-Боас
12

Я считаю, что столкнулся точно с той же проблемой. После бесчисленных часов борьбы с JSON, JavaScript и сервером я нашел виновника: в моем случае у меня был объект Date в DTO, этот объект Date был преобразован в строку, чтобы мы могли показать его в представлении с Формат: ЧЧ: мм.

Когда информация JSON отправлялась обратно, этот объект Date String необходимо было преобразовать обратно в полный объект Date, поэтому нам также необходим метод для его установки в DTO. Большое НО в том, что в DTO нельзя иметь 2 метода с одинаковым именем (Overload), даже если они имеют другой тип параметра (String vs Date), поскольку это также приведет к ошибке 415 Unsupported Media type.

Это был мой метод контроллера

  @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 (методы id get / set и preAlarm get не включены для краткости кода):

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

Чтобы все работало, вам нужно удалить метод с параметром Тип даты. Эта ошибка очень расстраивает. Надеюсь, что это может сэкономить кому-то часы отладки.

will824
источник
Спасибо - или вы можете просто переименовать одного из сеттеров. Я был как public void setParameters(List<Parameter> parameters)и public void setParameters(Parameter... parameters)методы в бобе, изменяя последнему addParametersрешен вопрос для меня.
Конор Свенссон
Разве проблема не в том, что тело это this.preAlarm == date, а не this.preAlarm = date?
Майкл восстановил Монику Челлио
12

Я столкнулся с подобной проблемой, и вот как я это исправил,

Проблема заключается в том, что процесс преобразования из JSON в Java требует правильных библиотек времени выполнения, чтобы преобразование происходило правильно.

Добавьте следующие jar-файлы (через зависимости или загрузив и добавив в classpath.

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

Надеюсь это поможет

vinSan
источник
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классе. Я не нашел статью, объясняющую это поведение, но решил это таким образом. Надеюсь, это полезно.

GC5
источник
Бывает же со мной! Любое объяснение, почему это происходит?
Причудливый
Можете ли вы объяснить ваш метод в деталях?
Дипаншу Верма
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

Пружинный ботинок + весенний мвн

с проблемой

@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 к моему pom.

<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;
Deko
источник
0

Я была такая же проблема. добавление

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

к весне-хмл решил

OhadR
источник