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

gc5
źródło
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.

theon
źródło
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
Używałem
21

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

uiroshan
źródło
18

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

John Shepherd
źródło
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.

will824
źródło
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

vinSan
źródło
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>
głęboki
źródło
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.

Carlos Romero
źródło
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.

gc5
źródło
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.

Manoj Shrestha
źródło
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){
Shahid Hussain Abbasi
źródło
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>
Lingasamy Bagavathi
źródło
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;
deko
źródło
0

Miałem ten sam problem. dodanie

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

rozwiązał go spring-xml

OhadR
źródło