Jquery - Como fazer $ .post () usar contentType = application / json?

309

Observei que, ao usar $ .post () no jquery, o contentType padrão é application / x-www-form-urlencoded - quando meu código asp.net mvc precisa ter contentType = application / json

(Consulte esta pergunta para saber por que devo usar application / json: ASPNET MVC - Por que ModelState.IsValid é falso "O campo x é obrigatório" quando esse campo tem um valor? )

Como posso fazer com que $ .post () envie contentType = application / json? Eu já tenho um grande número de funções $ .post (), então não quero mudar para $ .ajax () porque levaria muito tempo

Se eu tentar

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

Ele ainda possui contentType = application / x-www-form-urlencoded. Então, o que exatamente o parâmetro "json" faz se não altera o tipo de conteúdo para json?

Se eu tentar

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

Isso funciona, mas afeta todos os $ .get e $ .post que eu tenho e faz com que alguns sejam quebrados.

Então, existe alguma maneira de alterar o comportamento de $ .post () para enviar contentType = application / json?

JK.
fonte

Respostas:

71

Eu acho que você pode ter que

1.Modifique a fonte para fazer com que $ .post sempre use o tipo de dados JSON, pois é apenas um atalho para uma $.ajaxchamada pré-configurada

Ou

2. Defina sua própria função de utilitário que é um atalho para a $.ajaxconfiguração que você deseja usar

Ou

3.Você pode sobrescrever o arquivo $.post functioncom sua própria implementação através do patch do macaco.

O tipo de dados JSON no seu exemplo refere-se ao tipo de dados retornado do servidor e não ao formato enviado ao servidor.

Russ Cam
fonte
5
+1, gostaria de ir para a definição de um novo método, ou substituir jQuery.postmétodo, é uma função muito simples ...
CMS
3
Não é uma má idéia, basta criar um método chamado $ .mvcpost () que faça o mesmo que $ .post (copiando o código vinculado) e altere o tipo de conteúdo. Então, para todos os $ .post () s que precisam ser alterados, basta digitar 3 caracteres extras na frente. É muito mais rápido do que reescrevê-los como $ .ajax ().
JK.
9
@PavelRepin, tive que chamar JSON.stringify () na carga útil.
Ustaman Sangat
2
@dragon - aqui estão três soluções para "existe alguma maneira de alterar o comportamento de $ .post () para enviar contentType = application / json?". Que parte não é uma resposta?
Russ Cam
2
Também é importante saber: $ .ajax e seus vários métodos tentarão adivinhar qual deve ser o contentType (a menos que seja especificado) com base nos dados que você fornecer. "mystring data"estará application/x-www-form-urlencoded;onde um objeto { anyKey: "anyvalue and type" }estará application/json. Muitos servidores que lêem json permitem apenas um objeto ou matriz, não uma string - por isso, o jquery prevê as coisas dessa maneira. Se você possui um servidor que lê seqüências de caracteres, números, etc, sem ser envolvido em um objeto, deve especificar o tipo de conteúdo como nesta resposta.
bzuillsmith
395
$.ajax({
  url:url,
  type:"POST",
  data:data,
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  success: function(){
    ...
  }
})

Consulte: jQuery.ajax ()

Adrien
fonte
13
A postagem original pergunta: "Existe alguma maneira de alterar o comportamento de $ .post () para enviar contentType = application / json?" MAS também afirma "Isso funciona, mas afeta todos os posts $ .get e $ .post que tenho e causa a quebra de alguns". Entendo a pergunta como "como conseguir a mesma coisa que usar $ .post, mas enviar o contentType correto, sem interromper as outras ocorrências de $ .get e $ .post". Isso está incorreto?
Adrien
5
@ x1a4 claramente não entende que .ajax é a chamada, não ajaxSetup
Walker
39
@ Adrien, pelo que vale dois anos depois, a sua é a resposta que eu estava procurando quando pesquisei isso.
AwesomeTown
74
precisava usar JSON.stringify(data), pois o servidor espera uma string JSON e o jQuery simplesmente concatenaria os pares de valores-chave usando e comercial, codificado em forma de URL.
dragon
3
Mesmo quatro anos depois, essa resposta resolveu minhas horas de pesquisa com menos de dez linhas de código.
Pieter VDE
86

Finalmente encontrei a solução, que funciona para mim:

jQuery.ajax ({
    url: myurl,
    type: "POST",
    data: JSON.stringify({data:"test"}),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(){
        //
    }
});
vvkatwss vvkatwss
fonte
8
Não foi possível descobrir por que eu continuava recebendo erros, acontece que você precisa restringir os dados.
Zastrowm
5
Eu sei que isso funciona, mas POR QUE oh POR QUE você precisa restringir? É um bug do jQuery? Parece ser perfeitamente feliz serializar seu dataargumento x-www-form-urlencoded, mas se você indicar que o tipo de conteúdo da solicitação é JSON, ele ainda insistirá em enviar dataem um formato incompatível.
precisa saber é o seguinte
Bem. Eu não cavei muito. Fiquei feliz por estar funcionando. ;) Meu servidor requer JSON.
Vvkatwss vvkatwss
O mesmo aqui. Sem o JSON.stringify, ele não funciona, eu me pergunto o porquê.
precisa
42

Acabei adicionando o seguinte método ao jQuery no meu 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
    });
};

E para usá-lo

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

Isso foi feito simplesmente copiando o código de "get" e "post" das fontes originais do JQuery e codificando alguns parâmetros para forçar um JSON POST.

Obrigado!

continuidade
fonte
2
Como sempre - a melhor resposta vem por último para a festa e tem menos
votos positivos
Ótima resposta - demora um pouco para perceber que $ .post não faz isso "fora da caixa".
markp3rry
21

use apenas

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

ATUALIZADO @JK: Se você escrever em sua pergunta apenas um exemplo de código com $ .post, encontrará um exemplo correspondente na resposta. Não quero repetir as mesmas informações que você já estudou até saber: $ .post e $ .get são formas curtas de $ .ajax. Portanto, basta usar $ .ajax e você pode usar todo o conjunto de parâmetros sem precisar alterar nenhuma configuração global.

A propósito, eu não recomendaria substituir o $ .post padrão. É minha opinião pessoal , mas para mim é importante, não apenas que o programa funcione, mas também que todos que leem o seu programa o entendam da mesma maneira. A substituição de métodos padrão sem ter um motivo muito importante pode resultar em mal - entendidos na leitura do código do programa. Então, repito minha recomendação mais uma vez: basta usar o formulário $ .ajax original jQuery em vez de jQuery.gete jQuery.poste você recebe programas que não apenas funcionam perfeitamente, mas podem ser lidos por pessoas sem nenhum mal-entendido.

Oleg
fonte
1
Ótima explicação e orientação
Ved Prakash
8

O tipo de dados "json" que você pode passar como o último parâmetro para postar () indica que tipo de dados a função espera na resposta do servidor, não o tipo que está enviando na solicitação. Especificamente, ele define o cabeçalho "Accept".

Honestamente, sua melhor aposta é mudar para uma chamada ajax (). A função post () é uma conveniência; uma versão simplificada do ajax () solicita quando você está apenas enviando um simples formulário. Você não é.

Se você realmente não deseja alternar, pode criar sua própria função chamada, digamos, xpost (), e simplesmente transformá-los em parâmetros para uma chamada jQuery ajax (), com o tipo de conteúdo definido. Dessa forma, em vez de reescrever todas essas funções post () em funções ajax (), você só precisa alterá-las de post para xpost (ou o que for).

Jacob Mattison
fonte
São apenas os métodos $ .post () que chamam um método de controlador asp.net mvc que precisa ser alterado. Os jquery puros não devem ser alterados (preenchimento automático, diaplog, jqgrid etc.) Eu esperava que houvesse uma alteração simples que eu pudesse fazer nos $ .post () s relevantes. Mas parece que eu preciso convertê-los para $ .ajax (). É um aplicativo grande e muito ajax pesado, então há muitos deles para mudar.
JK.
6

Esta extensão simples da API jquery (de: https://benjamin-schweizer.de/jquerypostjson.html ) para $ .postJSON () faz o truque. Você pode usar o postJSON () como qualquer outra chamada nativa do jquery Ajax. Você pode anexar manipuladores de eventos e assim por diante.

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

Como outras APIs do Ajax (como $ http do AngularJS), ele define o contentType correto como application / json. Você pode passar seus dados json (objetos javascript) diretamente, uma vez que são estritamente aqui. O dataType retornado esperado é definido como JSON. Você pode anexar manipuladores de eventos padrão do jquery para promessas, por exemplo:

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

Eu sei que esta é uma resposta tardia, na verdade, tenho um método de atalho que eu uso para postar / ler para / de serviços baseados em MS .. ele funciona tanto com MVC quanto com ASMX, etc.

Usar:

$.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: Também tenho um método JSON.parseAjax modificado do arquivo JS do json.org, que adiciona manipulação para as datas "/Date(...)/" do MS ...

O arquivo json2.js modificado não está incluído, ele usa o analisador baseado em script no caso do IE8, pois há casos em que o analisador nativo é interrompido quando você estende o protótipo de matriz e / ou objeto, etc.

Estou pensando em renovar esse código para implementar as interfaces promissoras, mas funcionou muito bem para mim.

Tracker1
fonte
4

No cerne da questão está o fato de o JQuery no momento da redação não ter um método postJSON enquanto o getJSON existe e faz a coisa certa.

um método postJSON faria o seguinte:

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

e pode ser usado assim:

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

A documentação mostra atualmente que a partir de 3.0, $ .post aceitará as configurações do objeto, o que significa que você pode usar as opções $ .ajax. O 3.0 ainda não foi lançado e, no commit, eles estão falando sobre ocultar a referência a ele nos documentos, mas procure-a no futuro!

Ben Creasy
fonte
1

Eu tive um problema semelhante com o seguinte código JavaScript:

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

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

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

Onde no Violinista eu pude ver a solicitação com:

  • Cabeçalho: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Corpo: {"value":"5","maxValue":"5"}

Como resultado, meu servidor não pôde mapear um objeto para um tipo de servidor.

Depois de alterar a última linha para esta:

$.post(url, rating, showSavedNotification);

No Violinista eu ainda podia ver:

  • Cabeçalho: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • Corpo: value=5&maxValue=10

No entanto, o servidor começou a retornar o que eu esperava.

Oleg Burov
fonte
0

E o seu próprio adaptador / invólucro?

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

E uso extremamente simples:

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... }
});
Escurecimento
fonte
Tentei, mas ainda não obtive os resultados esperados. Eu tenho a API Spring Boot Rest.
Suraj Shingade 03/04/19
0

Por alguma razão, definir o tipo de conteúdo na solicitação ajax como sugerido por @Adrien não funcionou no meu caso. No entanto, você pode alterar o tipo de conteúdo usando $ .post fazendo isso antes:

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

Então faça sua $.postligação:

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

Eu tive problemas com o jQuery + IIS, e essa foi a única solução que ajudou o jQuery a entender o uso da codificação windows-1252 para solicitações de ajax.

Johannes
fonte
0

podemos mudar o tipo de conteúdo assim em $ .post

$ .post (url, dados, função (dados, status, xhr) {xhr.setRequestHeader ("Tipo de conteúdo", "aplicativo / x-www-form-urlencoded; charset = utf-8");});

Snziv Gupta
fonte
-1

$ .post não funciona se você tiver um problema de CORS (compartilhamento de recursos de origem cruzada). Tente usar $ .Ajax no seguinte formato: "$ .ajax ({url: someurl, contentType: 'application / json', dados: requestInJSONFormat, headers: {'Access-Control-Allow-Origin': '*'}, dataType: 'json', tipo: 'POST', assíncrono: falso, sucesso: função (Dados) {...}}); "

Soma Sarkar
fonte
-19

Você não pode enviar application/json diretamente - ele deve ser um parâmetro de uma solicitação GET / POST.

Então, algo como

$.post(url, {json: "...json..."}, function());
Amy B
fonte
Esta resposta pode estar incorreta, mas não é de baixa qualidade e é uma tentativa de responder à pergunta. Da revisão .
Wai Ha Lee