Impossible de définir le type de contenu sur 'application / json' dans jQuery.ajax

106

Quand j'ai ce code

$.ajax({
    type: 'POST',
    //contentType: "application/json",
    url: 'http://localhost:16329/Hello',
    data: { name: 'norm' },
    dataType: 'json'
});

dans Fiddler, je peux voir la requête brute suivante

POST http://localhost:16329/Hello HTTP/1.1
Host: localhost:16329
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:14693/WebSite1/index.html
Content-Length: 9
Origin: http://localhost:14693
Pragma: no-cache
Cache-Control: no-cache

name=norm

Mais ce que j'essaye, c'est de définir le type de contenu depuis application / x-www-form-urlencoded vers application / json . Mais ce code

$.ajax({
    type: "POST",
    contentType: "application/json",
    url: 'http://localhost:16329/Hello',
    data: { name: 'norm' },
    dataType: "json"
});

Génère une requête étrange (que je peux voir dans Fiddler)

OPTIONS http://localhost:16329/Hello HTTP/1.1
Host: localhost:16329
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Origin: http://localhost:14693
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Pragma: no-cache
Cache-Control: no-cache

Pourquoi donc? Quelles sont les OPTIONS alors qu'il devrait y avoir POST? Et où mon type de contenu est-il défini sur application / json? Et les paramètres de demande ont disparu pour une raison quelconque.

MISE À JOUR 1

Du côté du serveur, j'ai un service RESTful très simple.

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class RestfulService : IRestfulService
{
    [WebInvoke(
        Method = "POST",
        UriTemplate = "Hello",
        ResponseFormat = WebMessageFormat.Json)]
    public string HelloWorld(string name)
    {
        return "hello, " + name;
    }
}

Mais pour une raison quelconque, je ne peux pas appeler cette méthode avec des paramètres.

MISE À JOUR 2

Désolé de ne pas avoir répondu si longtemps.

J'ai ajouté ces en-têtes à la réponse de mon serveur

 Access-Control-Allow-Origin: *
 Access-Control-Allow-Headers: Content-Type
 Access-Control-Allow-Methods: POST, GET, OPTIONS

Cela n'a pas aidé, j'ai une erreur de méthode non autorisée du serveur.

Voici ce que dit mon violoneux

entrez la description de l'image ici

Donc, maintenant je peux être sûr que mon serveur accepte POST, GET, OPTIONS (si les en-têtes de réponse fonctionnent comme prévu). Mais pourquoi "Méthode non autorisée"?

Dans la réponse WebView du serveur (vous pouvez voir la réponse brute sur l'image ci-dessus) ressemble à ceci

entrez la description de l'image ici

Vitalii Korsakov
la source
2
vous devriez essayer la méthode JSON.stringfy ()
Amritpal Singh
Regardez ici. Cela fonctionne très bien pour moi: stackoverflow.com/questions/9754767/…
Fanda
J'ai exactement le même problème, mais je travaille avec NodeJS en tant que backend, j'ai également défini toutes les demandes OPTION non seulement pour être acceptées, mais pour forcer une réponse 200 sur toutes les demandes OPTION afin que le reste des pétitions fonctionne comme prévu sans réponse ...
HeberLZ
1
Salut @VitaliiKorsakov. Avez-vous résolu votre problème? Je rencontre le même problème, c'est à dire ne peut pas modifier contentType.
worldterminator
1
J'ai eu le même problème et je viens de le faire fonctionner .. la solution est dans la réponse sur cette page: stackoverflow.com/questions/20295080/… .. pour résumer: "Lors de l'utilisation de contentType: 'application / json' vous allez ne pas pouvoir compter sur le remplissage de $ _POST. $ _POST n'est rempli que pour les types de contenu codés par formulaire. En tant que tel, vous devez lire vos données à partir de l'entrée brute PHP ".. Je vois maintenant que vous n'utilisez pas php sur le serveur côté mais j'espère que cette information aide d'une certaine manière.
Sarah

Réponses:

91

Il semblerait que la suppression http://de l'option url garantit l'envoi de l'en-tête HTTP POST correct.

Je ne pense pas que vous ayez besoin de qualifier complètement le nom de l'hôte, utilisez simplement une URL relative comme ci-dessous.

   $.ajax({
      type: "POST",
      contentType: "application/json",
      url: '/Hello',
      data: { name: 'norm' },
      dataType: "json"
   });

Un exemple du mien qui fonctionne:

        $.ajax({
            type: "POST",
            url: siteRoot + "api/SpaceGame/AddPlayer",
            async: false,
            data: JSON.stringify({ Name: playersShip.name, Credits: playersShip.credits }),
            contentType: "application/json",
            complete: function (data) {
            console.log(data);
            wait = false;
        }
    });

Peut-être lié: jQuery $ .ajax (), $ .post envoyant "OPTIONS" comme REQUEST_METHOD dans Firefox

Edit: Après quelques recherches supplémentaires, j'ai découvert que l'en-tête OPTIONS est utilisé pour savoir si la demande du domaine d'origine est autorisée. En utilisant Fiddler, j'ai ajouté ce qui suit aux en-têtes de réponse de mon serveur.

 Access-Control-Allow-Origin: *
 Access-Control-Allow-Headers: Content-Type
 Access-Control-Allow-Methods: POST, GET, OPTIONS

Une fois que le navigateur a reçu cette réponse, il a ensuite envoyé la demande POST correcte avec les données json. Il semblerait que le type de contenu codé par url par défaut soit considéré comme sûr et ne subisse donc pas les vérifications interdomaines supplémentaires.

Il semble que vous devrez ajouter les en-têtes mentionnés précédemment à la réponse de votre serveur à la requête OPTIONS. Vous devez bien sûr les configurer pour autoriser les requêtes provenant de domaines spécifiques plutôt que tous.

J'ai utilisé le jQuery suivant pour tester cela.

$.ajax({
   type: "POST",
   url: "http://myDomain.com/path/AddPlayer",
   data: JSON.stringify({
      Name: "Test",
       Credits: 0
   }),
   //contentType: "application/json",
   dataType: 'json',
   complete: function(data) {
       $("content").html(data);
  }
});​

Références:

Mike Wade
la source
Je veux perdre le couplage entre le client et le serveur. Le serveur est un service RESTful et tous les clients de ce service doivent en connaître l'URL.
Vitalii Korsakov
Pouvez-vous fournir plus de détails dans votre article sur le scénario de cette question? Si vos clients doivent être sur des domaines différents, vous pouvez rencontrer les mêmes problèmes d'origine.
Mike Wade
J'ai publié des informations supplémentaires sur le côté serveur. À l'heure actuelle, le serveur et le client sont tous deux sur localhost mais diffèrent par le port. Plus tard, ils seront probablement sur des domaines différents.
Vitalii Korsakov
Il semble que le problème que vous rencontrez est lié à la même politique d'origine, cela pourrait valoir la peine de regarder jsonp et la question que j'ai liée dans ma réponse en plus de ces questions liées aux liens . jquery cross domain guide - Je n'ai pas beaucoup d'expérience avec les requêtes cross domain mais j'espère que ces liens vous seront utiles.
Mike Wade
Je ne pense pas que ce soit un problème car tout fonctionne bien lorsque je ne transmets aucun paramètre et que le type de contenu est application / x-www-form-urlencoded. Mais je n'ai pas besoin de demande POST si je ne peux passer aucun paramètre.
Vitalii Korsakov
41

Je peux te montrer comment je l'ai utilisé

  function GetDenierValue() {
        var denierid = $("#productDenierid").val() == '' ? 0 : $("#productDenierid").val();
        var param = { 'productDenierid': denierid };
        $.ajax({
            url: "/Admin/ProductComposition/GetDenierValue",
            dataType: "json",
            contentType: "application/json;charset=utf-8",
            type: "POST",
            data: JSON.stringify(param),
            success: function (msg) {
                if (msg != null) {
                    return msg.URL;
                }
            }
        });
    }
Amritpal Singh
la source
La même chose que dans la réponse suivante. Je ne peux pas ne pas spécifier l'URL du serveur où toutes les fonctions de service sont hébergées
Vitalii Korsakov
@VitaliiKorsakov je suis parti, avez-vous réglé votre problème.
Amritpal Singh
Merci d'avoir répondu! Je ne peux pas croire que ce n'est pas précisé ailleurs. Il semble bien que JQuery publierait json lorsque le type que vous spécifiez est `` json '', mais je suppose que non ...
Jason Goemaat
1
@JasonGoemaat le paramètre dataType dans jQuery est uniquement utilisé pour analyser le corps de la réponse renvoyée. Si vous lisez la documentation, vous verrez qu'elle n'est même pas nécessaire. La valeur par défaut de dataType est une estimation intelligente. Votre problème est que l'attribut de données dans jquery n'est pas configurable. Vous ne pouvez pas dire comment jquery doit analyser l'objet de données. C'est pourquoi vous devez sérialiser json avant. Parce que jquery ne sérialise qu'en url-form-encode
Loïc Faure-Lacroix
12

Donc, tout ce que vous devez faire pour que cela fonctionne est d'ajouter:

headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
}

comme champ à votre demande de message et cela fonctionnera.

Cody Jacques
la source
api.jquery.com/jquery.ajax Si vous regardez dans la documentation, il est dit que sans le spécifier, il est par défaut 'application / x-www-form-urlencoded; charset = UTF-8 '(c'est pourquoi cela se produit. Idk pourquoi le simple réglage de contentType ne fonctionne pas. Vous voudrez peut-être vérifier la version de jQuery que vous avez et mettre à jour si vous utilisez une ancienne version).
Cody Jacques
Cela ne fonctionne pas. Même si je l'ai fait type: "POST", il envoie OPTIONS.
user9645
5

J'ai reconnu ces écrans, j'utilise CodeFluentEntities et j'ai une solution qui a fonctionné pour moi aussi.

J'utilise cette construction:

$.ajax({
   url: path,
   type: "POST",
   contentType: "text/plain",
   data: {"some":"some"}
}

comme vous pouvez le voir, si j'utilise

contentType: "",

ou

contentType: "text/plain", //chrome

Tout fonctionne bien.

Je ne suis pas sûr à 100% que ce soit tout ce dont vous avez besoin, car j'ai également changé d'en-têtes.

Alexey Avdeyev
la source
5

Si vous utilisez ceci:

contentType: "application/json"

AJAX n'enverra pas les paramètres GET ou POST au serveur .... je ne sais pas pourquoi.

Il m'a fallu des heures pour l'apprendre aujourd'hui.

Utilisez simplement:

$.ajax(
  { url : 'http://blabla.com/wsGetReport.php',
    data : myFormData, type : 'POST', dataType : 'json', 
    // contentType: "application/json", 
    success : function(wsQuery) { }
  }
)
Luis Arturo Erique Guajala
la source
1
malheureusement la bonne réponse pour moi. Omettez contentType et utilisez simplement dataType pour contourner les déchets CORS OPTIONS que de nombreux services ne mettent tout simplement pas en œuvre correctement. Si ennuyant.
Umopepisdn
2

J'ai trouvé la solution à ce problème ici . N'oubliez pas d'autoriser les OPTIONS de verbe sur le gestionnaire de service d'application IIS.

Fonctionne très bien. Merci André Pedroso. :-)

Fanda
la source
1

J'ai eu le même problème. J'exécute une application java reste sur un serveur jboss. Mais je pense que la solution est similaire sur une application Web ASP .NET.

Firefox fait un appel préalable à votre serveur / URL de repos pour vérifier quelles options sont autorisées. C'est la requête "OPTIONS" à laquelle votre serveur ne répond pas en conséquence. Si cet appel OPTIONS reçoit une réponse correcte, un deuxième appel est effectué, qui est la requête "POST" réelle avec le contenu json.

Cela se produit uniquement lors d'un appel interdomaine. Dans votre cas, appelezhttp://localhost:16329/Hello ' au lieu d'appeler un chemin d'url sous le même domaine '/ Hello'

Si vous avez l'intention de faire un appel interdomaine, vous devez améliorer votre classe de service de repos avec une méthode annotée qui prend en charge une requête http "OPTIONS". Voici l'implémentation Java correspondante:

@Path("/rest")
public class RestfulService {

    @POST
    @Path("/Hello")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.TEXT_PLAIN)
    public string HelloWorld(string name)
    {
        return "hello, " + name;
    }

//THIS NEEDS TO BE ADDED ADDITIONALLY IF MAKING CROSS-DOMAIN CALLS

    @OPTIONS
    @Path("/Hello")
    @Produces(MediaType.TEXT_PLAIN+ ";charset=utf-8")
    public Response checkOptions(){
        return Response.status(200)
        .header("Access-Control-Allow-Origin", "*")
        .header("Access-Control-Allow-Headers", "Content-Type")
        .header("Access-Control-Allow-Methods", "POST, OPTIONS") //CAN BE ENHANCED WITH OTHER HTTP CALL METHODS 
        .build();
    }
}

Donc, je suppose que dans .NET, vous devez ajouter une méthode supplémentaire annotée avec

[WebInvoke(
        Method = "OPTIONS",
        UriTemplate = "Hello",
        ResponseFormat = WebMessageFormat.)]

où les en-têtes suivants sont définis

.header("Access-Control-Allow-Origin", "*")
        .header("Access-Control-Allow-Headers", "Content-Type")
        .header("Access-Control-Allow-Methods", "POST, OPTIONS")
Vincent
la source
0

J'ai eu la solution pour envoyer les données JSON par requête POST via jquery ajax. J'ai utilisé le code ci-dessous

    var data = new Object();
    data.p_clientId = 4;
    data =  JSON.stringify(data);

    $.ajax({
      method: "POST",
      url: "http://192.168.1.141:8090/api/Client_Add",
      data: data,
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'text/plain'
    }
    })
      .done(function( msg ) {
        alert( "Data Saved: " + msg );
      });


        });
    });

J'ai utilisé 'Content-Type': 'text/plain'dans l'en-tête pour envoyer les données json brutes.
Parce que si nous utilisons Content-Type: 'application/json'les méthodes de requête converties en OPTION, mais que l'utilisation de Content-Type: 'test/plain'la méthode ne se convertit pas et reste comme POST. Espérons que cela aidera quelqu'un.

Rahul Aparajit
la source
3
Ce n'est pas vraiment une conversion en OPTION, il envoie une demande de contrôle en amont CORS pour vérifier si le POST est autorisé. Lorsque cela ne revient pas correctement, le POST ne se produit pas.
Umopepisdn
0

Salut Ces deux lignes ont fonctionné pour moi.

contentType: "application / json; charset = utf-8", dataType: "json"

 $.ajax({
            type: "POST",
            url: "/v1/candidates",
            data: obj,
            **contentType:"application/json; charset=utf-8",
            dataType:"json",**
            success: function (data) {
                table.row.add([
                    data.name, data.title
                ]).draw(false);
            }

Merci, Prashant

Prashant Kumar
la source