Jquery - ¿Cómo hacer que $ .post () use contentType = application / json?

309

Me di cuenta de que cuando uso $ .post () en jquery, el tipo de contenido predeterminado es application / x-www-form-urlencoded, cuando mi código aspvc mvc necesita tener contentType = application / json

(Consulte esta pregunta para saber por qué debo usar application / json: ASPNET MVC - ¿Por qué es ModelState.IsValid falso "El campo x es obligatorio" cuando ese campo tiene un valor? )

¿Cómo puedo hacer que $ .post () envíe contentType = application / json? Ya tengo una gran cantidad de funciones $ .post (), así que no quiero cambiar a $ .ajax () porque tomaría demasiado tiempo

Si lo intento

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

Todavía tiene contentType = application / x-www-form-urlencoded. Entonces, ¿qué hace exactamente el parámetro "json" si no cambia el tipo de contenido a json?

Si lo intento

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

Eso funciona pero afecta a todos los $ .get y $ .post que tengo y hace que algunos se rompan.

Entonces, ¿hay alguna manera de que pueda cambiar el comportamiento de $ .post () para enviar contentType = application / json?

JK
fuente

Respuestas:

71

Creo que tienes que

1.Modifique la fuente para hacer que $ .post siempre use el tipo de datos JSON, ya que realmente es solo un acceso directo para una $.ajaxllamada preconfigurada

O

2. Defina su propia función de utilidad que es un acceso directo para la $.ajaxconfiguración que desea usar

O

3.Podrías sobrescribirlo $.post functioncon tu propia implementación a través de parches de mono.

El tipo de datos JSON en su ejemplo se refiere al tipo de datos devuelto por el servidor y no al formato enviado al servidor.

Russ Cam
fuente
55
+1, iría por definir un nuevo método, o sobreescribir el jQuery.postmétodo, es una función realmente simple ...
CMS
3
No es una mala idea, solo cree un método llamado $ .mvcpost () que haga lo mismo que $ .post (copiando el código vinculado) y cambie el tipo de contenido. Luego, para todos los $ .post () s que deben cambiarse, solo tengo que escribir 3 caracteres adicionales al frente. Es mucho más rápido que reescribirlos como $ .ajax ().
JK.
99
@PavelRepin, tuve que llamar a JSON.stringify () en la carga útil.
Ustaman Sangat el
2
@dragon: aquí hay 3 soluciones para "¿hay alguna manera de que pueda cambiar el comportamiento de $ .post () para enviar contentType = application / json?". ¿Qué parte no es una respuesta?
Russ Cam
2
También es importante saber: $ .ajax y sus diversos métodos intentarán adivinar cuál debe ser el tipo de contenido (a menos que se especifique) en función de los datos que le proporcione. "mystring data"será application/x-www-form-urlencoded;donde como un objeto { anyKey: "anyvalue and type" }será application/json. Muchos servidores que leen json solo permitirán un objeto o matriz, no una cadena, por lo que jquery predice las cosas de esta manera. Si tiene un servidor que lee cadenas, números, etc. sin estar envuelto en un objeto, debe especificar el tipo de contenido como en esta respuesta.
bzuillsmith
395
$.ajax({
  url:url,
  type:"POST",
  data:data,
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  success: function(){
    ...
  }
})

Ver: jQuery.ajax ()

Adrien
fuente
13
La publicación original pregunta: "Entonces, ¿hay alguna manera de que pueda cambiar el comportamiento de $ .post () para enviar contentType = application / json?" PERO también dice "Eso funciona pero afecta a cada $ .get y $ .post que tengo y hace que algunos se rompan". Entiendo la pregunta como "¿cómo puedo lograr lo mismo que usar $ .post pero enviando el tipo de contenido correcto sin romper las otras ocurrencias de $ .get y $ .post". ¿Eso es incorrecto?
Adrien
55
@ x1a4 claramente no entiende que .ajax es la llamada, no ajaxSetup
Walker
39
@Adrien, por lo que vale dos años después, la tuya es la respuesta que estaba buscando cuando busqué en Google.
AwesomeTown
74
tuvo que usar JSON.stringify(data), ya que el servidor espera una cadena JSON y jQuery simplemente concatenaría los pares de clave-valor usando símbolos "ampersands".
dragón
3
Incluso cuatro años después, esta respuesta ha resuelto mis horas de búsqueda con menos de diez líneas de código.
Pieter VDE
86

Finalmente encontré la solución, que funciona para mí:

jQuery.ajax ({
    url: myurl,
    type: "POST",
    data: JSON.stringify({data:"test"}),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(){
        //
    }
});
vvkatwss vvkatwss
fuente
8
No pude entender por qué seguía recibiendo errores, resulta que tienes que stringificar los datos.
zastrowm
55
Sé que esto funciona, pero ¿POR QUÉ, oh, POR QUÉ necesitas encadenar? ¿Es un error jQuery? Parece que está muy contento de serializar su dataargumento x-www-form-urlencoded, pero si indica que el tipo de contenido de la solicitud es JSON, todavía insiste en enviarlo dataen un formato no coincidente.
Pavel Repin
Bien. No lo cavé mucho. Estaba feliz de que funcionara. ;) Mi servidor requiere JSON.
vvkatwss vvkatwss
Igual que aquí. Sin JSON.stringify no funciona, me pregunto por qué.
John Simoes
42

Terminé agregando el siguiente método a jQuery en mi 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
    });
};

Y para usarlo

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

Esto se hizo simplemente copiando el código de "get" y "post" de las fuentes originales de JQuery y codificando algunos parámetros para forzar una POST DE JSON.

¡Gracias!

Kontinuity
fuente
2
Como de costumbre, la mejor respuesta es la última en la fiesta y tiene menos votos positivos; (
nikib3ro
Gran respuesta: lleva un tiempo darse cuenta de que $ .post no hace esto "fuera de la caja".
markp3rry
21

usar solo

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

ACTUALIZADO @JK: si escribe en su pregunta solo un ejemplo de código con $ .post, encontrará un ejemplo correspondiente en la respuesta. No quiero repetir la misma información que ya estudiaste hasta que sepas: $ .post y $ .get son formas cortas de $ .ajax. Tan solo use $ .ajax y puede usar el conjunto completo de sus parámetros sin tener que cambiar ninguna configuración global.

Por cierto, no recomendaría sobrescribir el $ .post estándar. Es mi opinión personal , pero para mí es importante, no solo que el programa funciona, sino también que todos los que leen tu programa lo entienden de la misma manera. Sobrescribir los métodos estándar sin tener una razón muy importante puede seguir a los malentendidos en la lectura del código del programa. Así que repito mi recomendación una vez más: simplemente use el formulario original $ .ajax jQuery en lugar de jQuery.gety, jQuery.posty recibirá programas que no solo funcionan perfectamente, sino que pueden ser leídos por personas sin malentendidos.

Oleg
fuente
1
Gran explicación y pauta
Ved Prakash
8

El tipo de datos "json" que puede pasar como el último parámetro para publicar () indica qué tipo de datos espera la función en la respuesta del servidor, no qué tipo está enviando en la solicitud. Específicamente establece el encabezado "Aceptar".

Honestamente, su mejor opción es cambiar a una llamada ajax (). La función post () se entiende como una conveniencia; una versión simplificada de la llamada ajax () para cuando solo está haciendo una publicación de formulario simple. No lo eres

Si realmente no desea cambiar, puede hacer que su propia función se llame, digamos, xpost (), y que simplemente transforme los parámetros dados en parámetros para una llamada jQuery ajax (), con el tipo de contenido establecido. De esa manera, en lugar de reescribir todas esas funciones post () en funciones ajax (), solo tiene que cambiarlas todas de post a xpost (o lo que sea).

Jacob Mattison
fuente
Solo los métodos $ .post () que llaman a un método de controlador asp.net mvc deben cambiar. Los jquery puros no deberían modificarse (autocompletar, diaplog, jqgrid, etc.) Esperaba que hubiera un cambio simple que pudiera hacer en los $ .post () s relevantes. Pero parece que necesito convertirlos a $ .ajax (). Es una aplicación grande y muy pesada, así que hay muchas para cambiar.
JK.
6

Esta extensión simple de API jquery (de: https://benjamin-schweizer.de/jquerypostjson.html ) por $ .postJSON () hace el truco. Puede usar postJSON () como cualquier otra llamada nativa de jquery Ajax. Puede adjuntar controladores de eventos, 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
  });
};

Al igual que otras API de Ajax (como $ http de AngularJS), establece el tipo de contenido correcto en application / json. Puede pasar sus datos json (objetos javascript) directamente, ya que aquí se encriptan. El tipo de datos devuelto esperado se establece en JSON. Puede adjuntar los controladores de eventos predeterminados de jquery para promesas, por ejemplo:

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

Sé que esta es una respuesta tardía, en realidad tengo un método de acceso directo que utilizo para publicar / leer en / desde servicios basados ​​en MS ... funciona con MVC y ASMX, etc.

Utilizar:

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

NOTA: También tengo un método JSON.parseAjax que se modifica del archivo JS de json.org, que agrega manejo para las fechas "/Date(...)/" de MS ...

El archivo json2.js modificado no está incluido, utiliza el analizador basado en scripts en el caso de IE8, ya que hay casos en los que el analizador nativo se rompe cuando extiende el prototipo de matriz y / u objeto, etc.

He estado considerando renovar este código para implementar las interfaces de promesas, pero me funcionó muy bien.

Rastreador1
fuente
4

El meollo del asunto es el hecho de que JQuery en el momento de la escritura no tiene un método postJSON mientras que getJSON existe y hace lo correcto.

un método postJSON haría lo siguiente:

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

y se puede usar así:

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

La documentación muestra actualmente que a partir de 3.0, $ .post aceptará el objeto de configuración, lo que significa que puede usar las opciones $ .ajax. 3.0 aún no se ha lanzado y en el commit están hablando de ocultar la referencia en los documentos, ¡pero búscalo en el futuro!

Ben Creasy
fuente
1

Tuve un problema similar con el siguiente código JavaScript:

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

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

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

Donde en el Fiddler pude ver la solicitud con:

  • Encabezamiento: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Cuerpo: {"value":"5","maxValue":"5"}

Como resultado, mi servidor no pudo asignar un objeto a un tipo del lado del servidor.

Después de cambiar la última línea a esta:

$.post(url, rating, showSavedNotification);

En el violinista todavía podía ver:

  • Encabezamiento: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Cuerpo: value=5&maxValue=10

Sin embargo, el servidor comenzó a devolver lo que esperaba.

Oleg Burov
fuente
0

¿Qué tal su propio adaptador / envoltura?

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

Y uso extremadamente 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... }
});
Ennegrecimiento
fuente
Intenté pero aún no obtengo los resultados esperados. Tengo Spring Boot Rest API.
Suraj Shingade
0

Por alguna razón, configurar el tipo de contenido en la solicitud ajax como @Adrien sugirió no funcionó en mi caso. Sin embargo, en realidad puede cambiar el tipo de contenido usando $ .post haciendo esto antes:

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

Entonces haz tu $.postllamada:

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

Tuve problemas con jQuery + IIS, y esta fue la única solución que ayudó a jQuery a comprender el uso de la codificación windows-1252 para las solicitudes ajax.

Johannes
fuente
0

podemos cambiar el tipo de contenido como este en $ .post

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

Snziv Gupta
fuente
-1

$ .post no funciona si tiene un problema CORS (Cross Origin Resource Sharing). Intente usar $ .Ajax en el siguiente formato: "$ .ajax ({url: someurl, contentType: 'application / json', data: requestInJSONFormat, headers: {'Access-Control-Allow-Origin': '*'}, dataType: 'json', tipo: 'POST', asíncrono: falso, éxito: función (Datos) {...}}); "

Soma Sarkar
fuente
-19

No puedes enviar application/json directamente, tiene que ser un parámetro de una solicitud GET / POST.

Entonces algo como

$.post(url, {json: "...json..."}, function());
Amy B
fuente
Esta respuesta puede ser incorrecta, pero no es de baja calidad, y es un intento de responder la pregunta. De la crítica .
Wai Ha Lee