POST JSON kończy się niepowodzeniem z 415 nieobsługiwanym typem multimediów, wiosna 3 mvc


171

Próbuję wysłać żądanie POST do serwletu. Żądanie jest wysyłane przez jQuery w następujący sposób:

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

gdzie jest newCategory

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

a postJSON jest

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

Z firebugiem widzę, że JSON jest wysyłany poprawnie:

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

Ale otrzymuję 415 Nieobsługiwany typ multimediów. Wiosenny kontroler mvc ma sygnaturę

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

Kilka dni temu działało, teraz nie. W razie potrzeby pokażę więcej kodu. Dzięki


Co zmieniłeś od kilku dni? Nie byłoby var productCategory = { idProductCategory: 1, description: "Descrizione2" };też bardziej zwięzłe i łatwiejsze do odczytania? Czy musisz powiedzieć Springowi, aby zaakceptował application/jsonkonkretnie? Innymi słowy, czy oczekuje, że dane przyjdą w formie?
— Dave Newton,

Sporo rzeczy, odkąd pracowałem nad inną częścią tego projektu, a dziś znalazłem ten regres. W tej części nic nie zmieniłem. Tak, muszę używać tego sposobu, ponieważ otrzymuję dane wejściowe z formularza.
— gc5

Nie, nie, otrzymujesz to z postu JSON Ajax, który nie jest tym samym, co dane zakodowane w formularzu.
— Dave Newton,

1
Czy na pewno Jackson jest nadal dostępny na Twoim CLASSPATH?
— Tomasz Nurkiewicz

1
jeśli wyślesz tekst / json zamiast application / json,
— pojawi

Odpowiedzi:


249

Zdarzało mi się to już wcześniej w przypadku Spring @ResponseBody i stało się tak, ponieważ z żądaniem nie wysłano nagłówka akceptacji. Zebrane nagłówek może być ból do zestawu z jQuery, ale ten pracował dla mnie źródło

$.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
    });
};

Nagłówek Content-Type jest używany przez @RequestBody do określenia formatu danych wysyłanych z klienta w żądaniu. Nagłówek accept jest używany przez @ResponseBody do określenia formatu, który ma odesłać dane do klienta w odpowiedzi. Dlatego potrzebujesz obu nagłówków.


1
nagłówki: {...} i JSON.stringify (...) zawsze mnie potykają.
— Tim Perry

1
Nie mam pojęcia, dlaczego nie jest to bardziej udokumentowane. Ten problem sprawił, że straciłem tyle czasu. Dziękuję Ci bardzo!
— Hugo Nava Kopp

Spodziewałem się, że Spring domyślnie obsługuje dane formularzy, ale tak nie jest. Więc dziękuję za (teraz dość stare) rozwiązanie.
— RiZKiT


21

dodanie typu zawartości do żądania jako application/jsonrozwiązało problem


18

Miałem podobny problem, ale stwierdziłem, że zaniedbałem dostarczenie domyślnego konstruktora dla DTO z adnotacją @RequestBody.


to samo przytrafiło się mnie. Miałem 2 metody o tej samej nazwie i otrzymywałem 415. Dzięki!
— Daniel Vilas-Boas

12

Wydaje mi się, że napotkałem dokładnie ten sam problem. Po niezliczonych godzinach walki z JSON, JavaScriptem i serwerem, znalazłem winowajcę: w moim przypadku miałem obiekt Date w DTO, ten obiekt Date został przekonwertowany na String, więc mogliśmy go pokazać w widoku za pomocą format: HH: mm.

Kiedy informacje JSON były wysyłane z powrotem, ten obiekt Date String musiał zostać przekonwertowany z powrotem na pełny obiekt Date, dlatego potrzebujemy również metody, aby ustawić go w DTO. Wielkie ALE polega na tym, że nie można mieć 2 metod o tej samej nazwie (Przeciążenie) w DTO, nawet jeśli mają one inny typ parametru (ciąg vs data), ponieważ spowoduje to również błąd 415 nieobsługiwanego typu nośnika.

To była moja metoda kontrolera

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

To był mój przykład DTO (metody get / set i preAlarm get nie są uwzględnione w przypadku skrócenia kodu):

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

Aby wszystko działało, musisz usunąć metodę z parametrem typu Date. Ten błąd jest bardzo frustrujący. Mam nadzieję, że zaoszczędzi to komuś godzin debugowania.


Dzięki - lub możesz po prostu zmienić nazwę jednego z ustawiaczy. Miałem obie public void setParameters(List<Parameter> parameters)i public void setParameters(Parameter... parameters)metody w fasoli, zmieniając tę ​​drugą, aby addParametersrozwiązać problem za mnie.
— Conor Svensson

Czy nie jest problemem to, że treść jest this.preAlarm == date, a nie this.preAlarm = date?
— Michael przywraca Monikę Cellio

12

Miałem podobny problem i tak to naprawiłem,

Problem wynika z procesu konwersji z formatu JSON na Javę, aby konwersja przebiegła poprawnie, trzeba mieć odpowiednie biblioteki json w czasie wykonywania.

Dodaj następujące pliki JAR (przez zależność lub pobierając i dodając do ścieżki klas.

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

To powinno rozwiązać problem.

Kompletny kod:

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

a podpis kontrolera wygląda następująco:

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

Mam nadzieję że to pomoże


Tylko jackson-databindjest wymagane.
— Alex78191

8

Napotkałem ten problem, gdy zintegrowałem but sprężynowy ze sprężyną MVC. Rozwiązałem to, dodając po prostu te zależności.

<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

Mała uwaga dodatkowa - natknąłem się na ten sam błąd podczas tworzenia aplikacji internetowej. Błąd, który znaleźliśmy podczas zabawy z usługą Firefox Poster, polegał na tym, że zarówno pola, jak i wartości w pliku Json powinny być ujęte w podwójne cudzysłowy. Na przykład..

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

W naszym przypadku wypełniliśmy json za pomocą javascript, co może być trochę zagmatwane, jeśli chodzi o radzenie sobie z pojedynczymi / podwójnymi cudzysłowami, z tego, co słyszałem.

To, co zostało powiedziane wcześniej w tym i innych postach, takie jak dołączanie nagłówków „Akceptuj” i „Typ treści”, ma również zastosowanie.

Mam nadzieję, że pomoże.


3

Udało mi się to zrobić. Powiedz mi, jeśli się mylę. Użyłem tylko jednego sposobu serializacji / deserializacji: usunąłem wszystkie adnotacje dotyczące tego ( @JSONSerializei @JSONDeserialize) i zarejestrowałem serializatory i deserializatory w CustomObjectMapperklasie. Nie znalazłem artykułu wyjaśniającego to zachowanie, ale rozwiązałem w ten sposób. Mam nadzieję, że to przydatne.


Mnie dzieje się to samo! Jakieś wyjaśnienie, dlaczego tak się dzieje?
— Kapryśny

Czy możesz szczegółowo wyjaśnić swoją metodę?
— Dipanshu Verma

1

Miałem ten sam problem. Musiałem wykonać następujące kroki, aby rozwiązać problem:

1. Upewnij się, że masz następujące zależności:

    <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. Utwórz następujący filtr:

    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. Zastosuj powyższy filtr dla żądań w pliku 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>

Mam nadzieję, że to komuś się przyda.


jackson-corejest zależnością od jackson-databind, więc nie trzeba jej bezpośrednio dodawać.
— Alex78191

1
Dlaczego konieczne jest dodanie filtra CORS?
— Alex78191

1

But sprężynowy + sprężyna MVN

z problemem

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

z roztworem

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

0

Rozwiązałem ten problem, dodając powiązanie danych jackson-json do mojego pom.

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

0

W klasie modelu dodaj adnotację właściwości JSON, miej również domyślny konstruktor

@JsonProperty("user_name")
private String userName;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;

0

Miałem ten sam problem. dodanie

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

rozwiązał go spring-xml


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.