Ошибка 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)

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


Что вы изменили с тех пор несколько дней назад? Кроме того, не 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решило проблему


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

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


Спасибо - или вы можете просто переименовать одного из сеттеров. Я был как 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) {

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


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

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

с проблемой

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

0

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

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

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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.