POST JSON échoue avec 415 type de support non pris en charge, Spring 3 mvc

171

J'essaye d'envoyer une requête POST à ​​un servlet. La requête est envoyée via jQuery de cette manière:

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

où est newCategory

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

et postJSON est

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

Avec firebug, je vois que JSON est envoyé correctement:

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

Mais j'obtiens 415 type de support non pris en charge. Le contrôleur Spring mvc a une signature

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

Il y a quelques jours, cela fonctionnait, maintenant ce n'est pas le cas. Je montrerai plus de code si nécessaire. Merci

gc5
la source
Qu'avez-vous changé depuis quelques jours? De plus, ne serait-il pas var productCategory = { idProductCategory: 1, description: "Descrizione2" };plus concis et plus facile à lire? Avez-vous besoin de dire à Spring d'accepter application/jsonspécifiquement? En d'autres termes, s'attend-il à ce que les données se présentent sous une forme?
Dave Newton
Beaucoup de choses depuis que je travaillais sur une autre partie de ce projet, et aujourd'hui j'ai trouvé cette régression. Dans cette partie je n'ai rien changé. Oui, je dois utiliser cette méthode car je reçois des informations à partir d'un formulaire.
gc5
Non, vous ne l'êtes pas, vous l'obtenez à partir d'une publication JSON Ajax, ce qui n'est pas la même chose que des données encodées sous forme de formulaire.
Dave Newton
1
Êtes-vous sûr que Jackson est toujours disponible sur votre CLASSPATH?
Tomasz Nurkiewicz
1
si vous envoyez du texte / json au lieu de l'application / json, vous obtenez la même erreur
Blacksonic

Réponses:

250

Cela s'est déjà produit avec Spring @ResponseBody et c'était parce qu'il n'y avait pas d'en-tête d'acceptation envoyé avec la demande. Accepter l'en-tête peut être difficile à définir avec jQuery, mais cela a fonctionné pour moi source

$.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'en-tête Content-Type est utilisé par @RequestBody pour déterminer le format des données envoyées par le client dans la demande. L'en-tête accept est utilisé par @ResponseBody pour déterminer le format dans lequel renvoyer les données au client dans la réponse. C'est pourquoi vous avez besoin des deux en-têtes.

theon
la source
1
les en-têtes: {...} et le JSON.stringify (...) me trébuchent toujours.
Tim Perry
1
Aucune idée pourquoi ce n'est pas plus documenté. Ce problème m'a fait perdre beaucoup de temps. Merci beaucoup!
Hugo Nava Kopp
Je m'attendais à ce que Spring prenne en charge les données de formulaire par défaut, mais ce n'est pas le cas. Alors, merci pour la solution (maintenant plutôt ancienne).
RiZKiT
J'utilisais un facteur pour faire une demande de mise, je viens d'ajouter le type de contenu: '' application / json ". Merci
Janatbek Sharsheyev
21

l'ajout du type de contenu dans la demande a application/jsonrésolu le problème

uiroshan
la source
18

J'ai eu un problème similaire, mais j'ai trouvé que j'avais négligé de fournir un constructeur par défaut pour le DTO qui était annoté avec @RequestBody.

John Shepherd
la source
1
Il m'est arrivé la même chose. J'avais 2 méthodes avec le même nom et recevais 415. Merci!
Daniel Vilas-Boas
12

Je crois que j'ai rencontré exactement le même problème. Après d'innombrables heures de combat avec le JSON, le JavaScript et le serveur, j'ai trouvé le coupable: dans mon cas, j'avais un objet Date dans le DTO, cet objet Date a été converti en String afin que nous puissions l'afficher dans la vue avec le format: HH: mm.

Lorsque les informations JSON étaient renvoyées, cet objet Date String devait être reconverti en un objet Date complet, nous avons donc également besoin d'une méthode pour le définir dans le DTO. Le gros MAIS est que vous ne pouvez pas avoir 2 méthodes avec le même nom (surcharge) dans le DTO même si elles ont un type de paramètre différent (chaîne vs date) car cela vous donnera également l'erreur de type 415 Unsupported Media.

C'était ma méthode de contrôleur

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

C'était mon exemple DTO (les méthodes id get / set et preAlarm get ne sont pas incluses pour la brièveté du code):

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

Pour que tout fonctionne, vous devez supprimer la méthode avec le paramètre de type Date. Cette erreur est très frustrante. J'espère que cela peut sauver quelqu'un des heures de débogage.

will824
la source
Merci - ou vous pouvez simplement renommer l'un des setters. J'avais les deux méthodes public void setParameters(List<Parameter> parameters)& public void setParameters(Parameter... parameters)dans un bean, changeant cette dernière pour addParametersrésoudre le problème pour moi.
Conor Svensson
Le problème n'est-il pas que le corps soit this.preAlarm == date plutôt que this.preAlarm = date?
Michael restaure Monica Cellio
12

J'ai rencontré un problème similaire et c'est ainsi que je l'ai résolu,

Le problème est dû au processus de conversion de JSON à Java, il faut avoir les bonnes bibliothèques jackson d'exécution pour que la conversion se déroule correctement.

Ajoutez les fichiers JAR suivants (via une dépendance ou en téléchargeant et en ajoutant au 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>

Cela devrait résoudre le problème.

Code complet:

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

et la signature du contrôleur ressemble à ceci:

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

J'espère que cela t'aides

vinSan
la source
Seul jackson-databindest requis.
Alex78191
8

J'ai rencontré ce problème lorsque j'ai intégré la botte à ressort avec Spring mvc. Je l'ai résolu en ajoutant simplement ces dépendances.

<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>
Profond
la source
5

Une petite note latérale - est tombé sur cette même erreur lors du développement d'une application Web. L'erreur que nous avons trouvée, en jouant avec le service avec Firefox Poster, était que les champs et les valeurs du Json devaient être entourés de guillemets. Par exemple..

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

Dans notre cas, nous avons rempli le json via javascript, ce qui peut être un peu déroutant lorsqu'il s'agit de traiter les guillemets simples / doubles, d'après ce que j'ai entendu.

Ce qui a déjà été dit dans cet article et dans d'autres, comme inclure les en-têtes `` Accepter '' et `` Type de contenu '', s'applique également.

Hope t'helps.

Carlos Romero
la source
3

J'ai réussi à le faire fonctionner. Dites-moi au cas où je me trompe. J'ai utilisé une seule façon de sérialiser / désérialiser: j'ai supprimé toutes les annotations concernant ceci ( @JSONSerializeet @JSONDeserialize) et enregistré les sérialiseurs et désérialiseurs en CustomObjectMapperclasse. Je n'ai pas trouvé d'article expliquant ce comportement mais j'ai résolu de cette manière. J'espère que c'est utile.

gc5
la source
Ça m'arrive la même chose! Une explication pourquoi cela arrive?
Whimusical
Pouvez-vous expliquer votre méthode en détail?
Dipanshu Verma
1

J'ai eu le même problème. J'ai dû suivre ces étapes pour résoudre le problème:

1. Assurez-vous que vous disposez des dépendances suivantes:

    <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. Créez le filtre suivant:

    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. Appliquez le filtre ci-dessus pour les demandes dans 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>

J'espère que cela sera utile à quelqu'un.

Manoj Shrestha
la source
jackson-coreest une dépendance de jackson-databind, donc pas besoin de l'ajouter directement.
Alex78191
1
Pourquoi est-il nécessaire d'ajouter le filtre CORS?
Alex78191
1

Botte à ressort + ressort MVN

avec problème

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

avec solution

@RequestMapping(value = "/addDonation", method = RequestMethod.POST)
@ResponseBody
public GenericResponse addDonation(final DonatorDTO donatorDTO, final HttpServletRequest request){
Shahid Hussain Abbasi
la source
0

J'ai résolu ce problème en ajoutant la liaison de données jackson-json à mon pom.

<dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.6.3</version>
</dependency>
Lingasamy Bagavathi
la source
0

Dans votre classe de modèle, ajoutez une annotation de propriété json, disposez également d'un constructeur par défaut

@JsonProperty("user_name")
private String userName;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;
deko
la source
0

J'ai eu le même problème. ajouter

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

au printemps-xml l'a résolu

OhadR
la source