Jquery - Comment faire pour que $ .post () utilise contentType = application / json?

309

J'ai remarqué que lors de l'utilisation de $ .post () dans jquery que le contentType par défaut est application / x-www-form-urlencoded - lorsque mon code mvc asp.net doit avoir contentType = application / json

(Voir cette question pour savoir pourquoi je dois utiliser application / json: ASPNET MVC - Pourquoi ModelState.IsValid false "Le champ x est requis" lorsque ce champ a une valeur? )

Comment puis-je faire en sorte que $ .post () envoie contentType = application / json? J'ai déjà un grand nombre de fonctions $ .post (), donc je ne veux pas passer à $ .ajax () car cela prendrait trop de temps

Si j'essaye

$.post(url, data, function(), "json") 

Il a toujours contentType = application / x-www-form-urlencoded. Alors, que fait exactement le paramètre "json" s'il ne change pas le type de contenu en json?

Si j'essaye

$.ajaxSetup({
  contentType: "application/json; charset=utf-8"
});

Cela fonctionne mais affecte tous les $ .get et $ .post que j'ai et provoque la rupture de certains.

Existe-t-il un moyen de changer le comportement de $ .post () pour envoyer contentType = application / json?

JK.
la source

Réponses:

71

Je pense que vous devrez peut-être

1.Modifiez la source pour que $ .post utilise toujours le type de données JSON car il ne s'agit en réalité que d'un raccourci pour un $.ajaxappel préconfiguré

Ou

2. Définissez votre propre fonction utilitaire qui est un raccourci pour la $.ajaxconfiguration que vous souhaitez utiliser

Ou

3.Vous pouvez remplacer le $.post functionpar votre propre implémentation via le patch de singe.

Le type de données JSON dans votre exemple fait référence au type de données renvoyé par le serveur et non au format envoyé au serveur.

Russ Cam
la source
5
+1, j'irais pour définir une nouvelle méthode, ou écraser la jQuery.postméthode, c'est une fonction vraiment simple ...
CMS
3
Ce n'est pas une mauvaise idée, créez simplement une méthode appelée $ .mvcpost () qui fait la même chose que $ .post (en copiant le code lié) et modifie le type de contenu. Ensuite, pour tous les $ .post () qui doivent être modifiés, je n'ai qu'à taper 3 caractères supplémentaires devant. C'est beaucoup plus rapide que de les réécrire en $ .ajax ().
JK.
9
@PavelRepin, j'ai dû appeler JSON.stringify () sur la charge utile.
Ustaman Sangat
2
@dragon - voici 3 solutions pour "est-il possible de changer le comportement de $ .post () pour envoyer contentType = application / json?". Quelle partie n'est pas une réponse?
Russ Cam
2
Il est également important de savoir: $ .ajax et ses différentes méthodes tenteront de deviner quel devrait être le contentType (sauf indication contraire) en fonction des données que vous lui fournissez. "mystring data"sera application/x-www-form-urlencoded;où comme un objet { anyKey: "anyvalue and type" }sera application/json. De nombreux serveurs qui lisent json n'autorisent qu'un objet ou un tableau, pas une chaîne - c'est pourquoi jquery prédit les choses de cette façon. Si vous avez un serveur qui lit des chaînes, des nombres, etc. sans être encapsulé dans un objet, vous devez spécifier le type de contenu comme dans cette réponse.
bzuillsmith
395
$.ajax({
  url:url,
  type:"POST",
  data:data,
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  success: function(){
    ...
  }
})

Voir: jQuery.ajax ()

Adrien
la source
13
Le message d'origine demande: "Alors, y a-t-il un moyen de changer le comportement de $ .post () pour envoyer contentType = application / json?" MAIS il indique également "Cela fonctionne mais affecte tous les $ .get et $ .post que j'ai et en provoque la rupture.". Je comprends la question comme "comment puis-je obtenir la même chose que d'utiliser $ .post mais en envoyant le bon contentType sans casser les autres occurrences de $ .get et $ .post". Est-ce que c'est incorrect?
Adrien
5
@ x1a4 ne comprend clairement pas que .ajax est l'appel, pas ajaxSetup
Walker
39
@Adrien, pour ce que ça vaut deux ans plus tard, la vôtre est la réponse que je cherchais quand j'ai fait une recherche sur Google.
AwesomeTown
74
a dû utiliser JSON.stringify(data), car le serveur attend une chaîne JSON et jQuery concaténerait simplement les paires clé-valeur en utilisant des esperluettes, form-urlencoded.
dragon
3
Même quatre ans plus tard, cette réponse a résolu mes heures de recherche avec moins de dix lignes de code.
Pieter VDE
86

Enfin, j'ai trouvé la solution qui me convient:

jQuery.ajax ({
    url: myurl,
    type: "POST",
    data: JSON.stringify({data:"test"}),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(){
        //
    }
});
vvkatwss vvkatwss
la source
8
Impossible de comprendre pourquoi j'ai continué à recevoir des erreurs, il s'avère que vous devez filtrer les données.
zastrowm
5
Je sais que cela fonctionne, mais POURQUOI oh POURQUOI avez-vous besoin de filtrer? Est-ce un bug jQuery? Il semble être parfaitement heureux de sérialiser votre dataargument x-www-form-urlencoded, mais si vous indiquez que le type de contenu de la demande est JSON, il insiste toujours sur l'envoi datadans un format non adapté.
Pavel Repin
Bien. Je ne l'ai pas beaucoup creusé. J'étais content que ça marche. ;) Mon serveur nécessite JSON.
vvkatwss vvkatwss
Pareil ici. Sans JSON.stringify, cela ne fonctionne pas, je me demande pourquoi.
John Simoes
42

J'ai fini par ajouter la méthode suivante à jQuery dans mon script:

jQuery["postJSON"] = function( url, data, callback ) {
    // shift arguments if data argument was omitted
    if ( jQuery.isFunction( data ) ) {
        callback = data;
        data = undefined;
    }

    return jQuery.ajax({
        url: url,
        type: "POST",
        contentType:"application/json; charset=utf-8",
        dataType: "json",
        data: data,
        success: callback
    });
};

Et pour l'utiliser

$.postJSON('http://url', {data: 'goes', here: 'yey'}, function (data, status, xhr) {
    alert('Nailed it!')
});

Cela a été fait en copiant simplement le code "get" et "post" à partir des sources JQuery d'origine et en codant en dur quelques paramètres pour forcer un POST JSON.

Merci!

continuité
la source
2
Comme d'habitude - la meilleure réponse arrive en dernier et a le moins de votes positifs; (
nikib3ro
Excellente réponse - il faut un certain temps pour réaliser que $ .post ne fait pas cela "hors de la boîte".
markp3rry
21

utiliser juste

jQuery.ajax ({
    url: myurl,
    type: "POST",
    data: mydata,
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(){
        //
    }
});

MISE À JOUR @JK: Si vous écrivez dans votre question un seul exemple de code avec $ .post, vous trouverez un exemple correspondant dans la réponse. Je ne veux pas répéter les mêmes informations que vous avez déjà étudiées jusqu'à présent: $ .post et $ .get sont des formes abrégées de $ .ajax. Il suffit donc d'utiliser $ .ajax et vous pouvez utiliser l'ensemble complet de ses paramètres sans avoir à modifier les paramètres globaux.

Au fait, je ne recommanderais pas d'écraser le $ .post standard. C'est mon opinion personnelle , mais pour moi, c'est important, non seulement que le programme fonctionne, mais aussi que tous ceux qui lisent votre programme le comprennent de la même manière. L'écrasement des méthodes standard sans avoir une raison très importante peut entraîner un malentendu lors de la lecture du code du programme. Je répète donc ma recommandation une fois de plus: utilisez simplement le formulaire original $ .ajax jQuery au lieu de jQuery.getet jQuery.postet vous recevez des programmes qui fonctionnent non seulement parfaitement, mais peuvent être lus par des personnes sans aucun malentendu.

Oleg
la source
1
Grande explication et ligne directrice
Ved Prakash
8

Le type de données "json" que vous pouvez passer comme dernier paramètre à post () indique le type de données que la fonction attend dans la réponse du serveur, pas le type qu'elle envoie dans la demande. Plus précisément, il définit l'en-tête "Accepter".

Honnêtement, votre meilleur pari est de passer à un appel ajax (). La fonction post () est conçue comme une commodité; une version simplifiée de l'appel ajax () pour quand vous faites juste une publication de formulaire simple. Tu ne l'es pas.

Si vous ne voulez vraiment pas changer, vous pouvez créer votre propre fonction appelée, par exemple, xpost (), et la transformer simplement en paramètres pour un appel jQuery ajax (), avec le type de contenu défini. De cette façon, plutôt que de réécrire toutes ces fonctions post () en fonctions ajax (), il vous suffit de les changer de post en xpost (ou autre).

Jacob Mattison
la source
Ce ne sont que les méthodes $ .post () qui appellent une méthode de contrôleur mvc asp.net qui doivent changer. Les jquery purs devraient être inchangés (saisie semi-automatique, diaplog, jqgrid, etc.) J'espérais qu'il y aurait un simple changement que je pourrais apporter aux $ .post () pertinents. Mais il semble que je doive les convertir en $ .ajax (). C'est une application lourde et très ajax, donc il y en a beaucoup à changer.
JK.
6

Cette simple extension d'API jquery (à partir de: https://benjamin-schweizer.de/jquerypostjson.html ) pour $ .postJSON () fait l'affaire. Vous pouvez utiliser postJSON () comme tout autre appel Ajax natif jquery. Vous pouvez attacher des gestionnaires d'événements, etc.

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

Comme d'autres API Ajax (comme $ http d'AngularJS), il définit le bon contentType sur application / json. Vous pouvez transmettre vos données json (objets javascript) directement, car elles sont ici strictes. Le type de données renvoyé attendu est défini sur JSON. Vous pouvez attacher les gestionnaires d'événements par défaut de jquery pour les promesses, par exemple:

$.postJSON(apiURL, jsonData)
 .fail(function(res) {
   console.error(res.responseText);
 })
 .always(function() {
   console.log("FINISHED ajax post, hide the loading throbber");
 });
Ruwen
la source
5

Je sais que c'est une réponse tardive, j'ai en fait une méthode de raccourci que j'utilise pour publier / lire vers / depuis les services basés sur MS .. cela fonctionne avec MVC ainsi qu'avec ASMX etc ...

Utilisation:

$.msajax(
  '/services/someservice.asmx/SomeMethod'
  ,{}  /*empty object for nothing, or object to send as Application/JSON */
  ,function(data,jqXHR) {
    //use the data from the response.
  }
  ,function(err,jqXHR) {
    //additional error handling.
  }
);
//sends a json request to an ASMX or WCF service configured to reply to JSON requests.
(function ($) {
  var tries = 0; //IE9 seems to error out the first ajax call sometimes... will retry up to 5 times

  $.msajax = function (url, data, onSuccess, onError) {
    return $.ajax({
      'type': "POST"
      , 'url': url
      , 'contentType': "application/json"
      , 'dataType': "json"
      , 'data': typeof data == "string" ? data : JSON.stringify(data || {})
      ,beforeSend: function(jqXHR) {
        jqXHR.setRequestHeader("X-MicrosoftAjax","Delta=true");
      }
      , 'complete': function(jqXHR, textStatus) {
        handleResponse(jqXHR, textStatus, onSuccess, onError, function(){
          setTimeout(function(){
            $.msajax(url, data, onSuccess, onError);
          }, 100 * tries); //try again
        });
      }
    });
  }

  $.msajax.defaultErrorMessage = "Error retreiving data.";


  function logError(err, errorHandler, jqXHR) {
    tries = 0; //reset counter - handling error response

    //normalize error message
    if (typeof err == "string") err = { 'Message': err };

    if (console && console.debug && console.dir) {
      console.debug("ERROR processing jQuery.msajax request.");
      console.dir({ 'details': { 'error': err, 'jqXHR':jqXHR } });
    }

    try {
      errorHandler(err, jqXHR);
    } catch (e) {}
    return;
  }


  function handleResponse(jqXHR, textStatus, onSuccess, onError, onRetry) {
    var ret = null;
    var reterr = null;
    try {
      //error from jqXHR
      if (textStatus == "error") {
        var errmsg = $.msajax.defaultErrorMessage || "Error retreiving data.";

        //check for error response from the server
        if (jqXHR.status >= 300 && jqXHR.status < 600) {
          return logError( jqXHR.statusText || msg, onError, jqXHR);
        }

        if (tries++ < 5) return onRetry();

        return logError( msg, onError, jqXHR);
      }

      //not an error response, reset try counter
      tries = 0;

      //check for a redirect from server (usually authentication token expiration).
      if (jqXHR.responseText.indexOf("|pageRedirect||") > 0) {
        location.href = decodeURIComponent(jqXHR.responseText.split("|pageRedirect||")[1].split("|")[0]).split('?')[0];
        return;
      }

      //parse response using ajax enabled parser (if available)
      ret = ((JSON && JSON.parseAjax) || $.parseJSON)(jqXHR.responseText);

      //invalid response
      if (!ret) throw jqXHR.responseText;  

      // d property wrap as of .Net 3.5
      if (ret.d) ret = ret.d;

      //has an error
      reterr = (ret && (ret.error || ret.Error)) || null; //specifically returned an "error"

      if (ret && ret.ExceptionType) { //Microsoft Webservice Exception Response
        reterr = ret
      }

    } catch (err) {
      reterr = {
        'Message': $.msajax.defaultErrorMessage || "Error retreiving data."
        ,'debug': err
      }
    }

    //perform final logic outside try/catch, was catching error in onSuccess/onError callbacks
    if (reterr) {
      logError(reterr, onError, jqXHR);
      return;
    }

    onSuccess(ret, jqXHR);
  }

} (jQuery));

REMARQUE: J'ai également une méthode JSON.parseAjax qui est modifiée à partir du fichier JS de json.org, qui ajoute la gestion des dates MS "/Date(...)/" ...

Le fichier json2.js modifié n'est pas inclus, il utilise l'analyseur basé sur un script dans le cas d'IE8, car il y a des cas où l'analyseur natif se casse lorsque vous étendez le prototype du tableau et / ou de l'objet, etc.

J'ai envisagé de réorganiser ce code pour implémenter les interfaces promises, mais cela a très bien fonctionné pour moi.

Tracker1
la source
4

Au cœur du problème se trouve le fait que JQuery au moment de la rédaction n'a pas de méthode postJSON alors que getJSON existe et fait la bonne chose.

une méthode postJSON ferait ce qui suit:

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

et peut être utilisé comme ceci:

postJSON( 'path/to/server', my_JS_Object_or_Array )
    .done(function (data) {
        //do something useful with server returned data
        console.log(data);
    })
    .fail(function (response, status) {
        //handle error response
    })
    .always(function(){  
      //do something useful in either case
      //like remove the spinner
    });
dbrin
la source
1

La documentation montre actuellement qu'à partir de la version 3.0, $ .post acceptera l'objet settings, ce qui signifie que vous pouvez utiliser les options $ .ajax. 3.0 n'est pas encore sorti et sur le commit ils parlent de cacher la référence dans les documents, mais cherchez-le à l'avenir!

Ben Creasy
la source
1

J'ai eu un problème similaire avec le code JavaScript suivant:

var url = 'http://my-host-name.com/api/Rating';

var rating = { 
  value: 5,
  maxValue: 10
};

$.post(url, JSON.stringify(rating), showSavedNotification);

Où dans le violoniste je pouvais voir la demande avec:

  • Entête: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Corps: {"value":"5","maxValue":"5"}

Par conséquent, mon serveur n'a pas pu mapper un objet sur un type côté serveur.

Après avoir changé la dernière ligne en celle-ci:

$.post(url, rating, showSavedNotification);

Dans le Fiddler, je pouvais encore voir:

  • Entête: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Corps: value=5&maxValue=10

Cependant, le serveur a commencé à renvoyer ce que j'attendais.

Oleg Burov
la source
0

Que diriez-vous de votre propre adaptateur / wrapper?

//adapter.js
var adapter = (function() {

return {

    post: function (url, params) {
        adapter.ajax(url, "post", params);
        },
    get: function (url, params) {
        adapter.ajax(url, "get", params);
    },
    put: function (url, params) {
        adapter.ajax(url, "put", params);
    },
    delete: function (url, params) {
        adapter.ajax(url, "delete", params);
    },
    ajax: function (url, type, params) {
        var ajaxOptions = {
            type: type.toUpperCase(),
            url: url,
            success: function (data, status) {
                var msgType = "";
                // checkStatus here if you haven't include data.success = true in your
                // response object
                if ((params.checkStatus && status) || 
                   (data.success && data.success == true)) {
                            msgType = "success";
                            params.onSuccess && params.onSuccess(data);
                    } else {
                            msgType = "danger";
                            params.onError && params.onError(data);
                    }
            },
            error: function (xhr) {
                    params.onXHRError && params.onXHRError();
                    //api.showNotificationWindow(xhr.statusText, "danger");
            }
        };
        if (params.data) ajaxOptions.data = params.data;
        if (api.isJSON(params.data)) {
            ajaxOptions.contentType = "application/json; charset=utf-8";
            ajaxOptions.dataType = "json";
        }
        $.ajax($.extend(ajaxOptions, params.options));
    }
})();

    //api.js
var api = {
  return {
    isJSON: function (json) {
        try {
            var o = JSON.parse(json);
            if (o && typeof o === "object" && o !== null) return true;
        } catch (e) {}
        return false;
    }
  }
})();

Et une utilisation extrêmement simple:

adapter.post("where/to/go", {
    data: JSON.stringify(params),
    onSuccess: function (data) {
        //on success response...
    }
    //, onError: function(data) {  //on error response... }
    //, onXHRError: function(xhr) {  //on XHR error response... }
});
Noircissement
la source
J'ai essayé, mais je n'obtiens toujours pas les résultats escomptés. j'ai l'API Spring Boot Rest.
Suraj Shingade
0

Pour une raison quelconque, la définition du type de contenu sur la demande ajax comme l'a suggéré @Adrien n'a pas fonctionné dans mon cas. Cependant, vous pouvez réellement changer le type de contenu à l'aide de $ .post en procédant comme suit avant:

$.ajaxSetup({
    'beforeSend' : function(xhr) {
        xhr.overrideMimeType('application/json; charset=utf-8');
    },
});

Faites ensuite votre $.postappel:

$.post(url, data, function(), "json")

J'ai eu des problèmes avec jQuery + IIS, et c'était la seule solution qui a aidé jQuery à comprendre l'utilisation du codage windows-1252 pour les requêtes ajax.

Johannes
la source
0

nous pouvons changer le type de contenu comme ceci dans $ .post

$ .post (url, data, function (data, status, xhr) {xhr.setRequestHeader ("Content-type", "application / x-www-form-urlencoded; charset = utf-8");});

Snziv Gupta
la source
-1

$ .post ne fonctionne pas si vous avez un problème CORS (Cross Origin Resource Sharing). Essayez d'utiliser $ .Ajax au format suivant: "$ .ajax ({url: someurl, contentType: 'application / json', data: requestInJSONFormat, en- têtes: {'Access-Control-Allow-Origin': '*'}, dataType: 'json', type: 'POST', async: false, success: function (Data) {...}}); "

Soma Sarkar
la source
-19

Vous ne pouvez pas envoyer application/jsondirectement - cela doit être un paramètre d'une demande GET / POST.

Donc quelque chose comme

$.post(url, {json: "...json..."}, function());
Amy B
la source
Cette réponse peut être incorrecte, mais elle n'est pas de mauvaise qualité et c'est une tentative de répondre à la question. De l'avis .
Wai Ha Lee