POST JSON non riesce con 415 tipo di supporto non supportato, Spring 3 mvc


171

Sto cercando di inviare una richiesta POST a un servlet. La richiesta viene inviata tramite jQuery in questo modo:

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

dove si trova newCategory

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

e postJSON è

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

Con firebug vedo che JSON viene inviato correttamente:

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

Ma ottengo 415 tipo di supporto non supportato. Il controller Spring PVC ha la firma

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

Alcuni giorni fa ha funzionato, ora non lo è. Mostrerò più codice se necessario. Grazie


Cosa sei cambiato da qualche giorno? Inoltre, non var productCategory = { idProductCategory: 1, description: "Descrizione2" };sarebbe più conciso e più facile da leggere? Devi dire a Spring di accettare in modo application/jsonspecifico? In altre parole, si aspetta che i dati vengano in un modulo?
Dave Newton,

Molte cose da quando stavo lavorando su un'altra parte di questo progetto, e oggi ho trovato questa regressione. In questa parte non ho cambiato nulla. Sì, devo usare in questo modo perché sto ricevendo input da un modulo.
gc5,

No, non lo sei, lo ricevi da un post Ajax JSON, che non è lo stesso dei dati codificati.
Dave Newton,

1
Sei sicuro che Jackson sia ancora disponibile sul tuo CLASSPATH?
Tomasz Nurkiewicz,

1
se invii text / json invece dell'applicazione / json ricevi lo stesso errore
Blacksonic

Risposte:


250

L'ho già accaduto in precedenza con Spring @ResponseBody ed è stato perché non è stata inviata alcuna intestazione di accettazione con la richiesta. Accettare l'intestazione può essere una seccatura da impostare con jQuery, ma questo ha funzionato per me fonte

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

L'intestazione Content-Type viene utilizzata da @RequestBody per determinare in quale formato sono i dati inviati dal client nella richiesta. L'intestazione accetta viene utilizzata da @ResponseBody per determinare quale formato restituire i dati al client nella risposta. Ecco perché hai bisogno di entrambe le intestazioni.


1
le intestazioni: {...} e JSON.stringify (...) mi fanno sempre inciampare.
Tim Perry,

1
Non ho idea del perché questo non sia più documentato. Questo problema mi ha fatto perdere così tanto tempo. Grazie mille!
Hugo Nava Kopp,

Mi aspettavo che Spring supporta i dati dei moduli per impostazione predefinita, ma non lo è. Quindi, grazie per la soluzione (ora piuttosto vecchia).
RiZKiT

Stavo usando un postino per fare una richiesta put, appena aggiunto il tipo di contenuto: '' application / json ". Grazie
Janatbek Sharsheyev

21

aggiungendo il tipo di contenuto nella richiesta come application/jsonrisolto il problema


18

Ho avuto un problema simile, ma ho scoperto che avevo trascurato di fornire un costruttore predefinito per il DTO che era stato annotato con @RequestBody.


1
La stessa cosa è successa a me. Avevo 2 metodi con lo stesso nome e stavo ottenendo 415. Grazie!
Daniel Vilas-Boas,

12

Credo di essermi imbattuto esattamente nello stesso problema. Dopo innumerevoli ore di combattimento con JSON, JavaScript e Server, ho trovato il colpevole: nel mio caso avevo un oggetto Date nel DTO, questo oggetto Date è stato convertito in una stringa in modo da poterlo mostrare nella vista con il formato: HH: mm.

Quando le informazioni JSON venivano restituite, questo oggetto String data doveva essere riconvertito in un oggetto Date completo, quindi abbiamo anche bisogno di un metodo per impostarlo nel DTO. Il grande MA è che non puoi avere 2 metodi con lo stesso nome (sovraccarico) nel DTO anche se hanno un diverso tipo di parametro (String vs Date) perché questo ti darà anche l'errore del tipo di supporto non supportato 415.

Questo era il mio metodo di controllo

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

Questo è stato il mio esempio DTO (i metodi id get / set e preAlarm get non sono inclusi per la mancanza di codice):

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

Per far funzionare tutto è necessario rimuovere il metodo con il parametro Tipo data. Questo errore è molto frustrante. Spero che questo possa far risparmiare a qualcuno ore di debug.


Grazie - oppure puoi semplicemente rinominare uno dei setter. Ho avuto entrambi public void setParameters(List<Parameter> parameters)e public void setParameters(Parameter... parameters)metodi in un fagiolo, cambiando quest'ultimo a addParametersrisolto il problema per me.
Conor Svensson,

Non è il problema che il corpo è this.preAlarm == date anziché this.preAlarm = date?
Michael ripristina Monica Cellio il

12

Ho affrontato un problema simile ed è così che l'ho risolto,

Il problema è dovuto al processo di conversione da JSON a Java, è necessario disporre delle librerie jackson runtime corrette per consentire la corretta conversione.

Aggiungi i seguenti vasetti (tramite dipendenza o scaricando e aggiungendo al percorso di classe.

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

Questo dovrebbe risolvere il problema.

Codice completo:

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

e la firma del controller si presenta così:

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

Spero che questo ti aiuti


È jackson-databindrichiesto solo.
Alex78191,

8

Ho riscontrato questo problema quando ho integrato lo stivale a molla con mvc a molla. L'ho risolto semplicemente aggiungendo queste dipendenze.

<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

Una piccola nota a margine: ci siamo imbattuti in questo stesso errore durante lo sviluppo di un'applicazione web. L'errore che abbiamo riscontrato, giocando con il servizio con Firefox Poster, è stato che entrambi i campi e i valori in Json devono essere racchiusi tra virgolette doppie. Per esempio..

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

Nel nostro caso abbiamo riempito il json tramite javascript, il che può essere un po 'confuso quando si tratta di trattare citazioni singole / doppie, da quello che ho sentito.

Si applica anche ciò che è stato detto in precedenza in questo e in altri post, come ad esempio le intestazioni "Accetta" e "Tipo di contenuto".

Spero ti aiuti.


3

Sono riuscito a farlo funzionare. Dimmi se ho torto. Ho usato solo un modo per serializzare / deserializzare: ho rimosso tutte le annotazioni relative a questo ( @JSONSerializee @JSONDeserialize) e ho registrato serializzatori e deserializzatori in CustomObjectMapperclasse. Non ho trovato un articolo che spiegasse questo comportamento, ma ho risolto in questo modo. Spero sia utile.


Succede lo stesso per me! Qualche spiegazione perché succede?
Whimusical,

Puoi per favore spiegare il tuo metodo in dettaglio ??
Dipanshu Verma,

1

Ho avuto lo stesso problema. Ho dovuto seguire questi passaggi per risolvere il problema:

1.Assicurati di avere le seguenti dipendenze:

    <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. Creare il seguente filtro:

    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. Applicare il filtro sopra per le richieste in 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>

Spero che questo sia utile a qualcuno.


jackson-coreè una dipendenza di jackson-databind, quindi non è necessario aggiungerlo direttamente.
Alex78191,

1
Perché è necessario aggiungere il filtro CORS?
Alex78191,

1

Stivale a molla + molla mvn

con problema

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

con soluzione

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

0

Ho risolto questo problema aggiungendo i dati jackson-json al mio pom.

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

0

Nella tua classe di modello aggiungi un'annotazione della proprietà json, inoltre hai un costruttore predefinito

@JsonProperty("user_name")
private String userName;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;

0

Ho avuto lo stesso problema. aggiungendo

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

al spring-xml risolto


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.