Jquery - How to make $.post() use contentType=application/json?
Asked Answered
B

17

354

I've noticed that when using $.post() in jquery that the default contentType is application/x-www-form-urlencoded - when my asp.net mvc code needs to have contentType=application/json

(See this question for why I must use application/json: ASPNET MVC - Why is ModelState.IsValid false "The x field is required" when that field does have a value?)

How can I make $.post() send contentType=application/json? I already have a large number of $.post() functions, so I don't want to change to $.ajax() because it would take too much time

If I try

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

It still has contentType=application/x-www-form-urlencoded. So what exactly does the "json" param do if it does not change the contenttype to json?

If I try

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

That works but affects every single $.get and $.post that I have and causes some to break.

So is there some way that I can change the behavior of $.post() to send contentType=application/json?

Bewitch answered 16/5, 2010 at 21:1 Comment(0)
E
77

I think you may have to

1.Modify the source to make $.post always use JSON data type as it really is just a shortcut for a pre configured $.ajax call

Or

2.Define your own utility function that is a shortcut for the $.ajax configuration you want to use

Or

3.You could overwrite the $.post function with your own implementation via monkey patching.

The JSON datatype in your example refers to the datatype returned from the server and not the format sent to the server.

Exegete answered 16/5, 2010 at 21:5 Comment(7)
+1, I would go for defining a new method, or overwriting jQuery.post method, it's a really simple function...Pierides
Its not a bad idea, just create a method called $.mvcpost() that does the same as $.post (by copying the linked code) plus changes the contenttype. Then for all the $.post()s that need to be changed, I just have to type 3 extra characters in front. Its much quicker than rewriting them as $.ajax().Bewitch
I have implemented this and its working well. No side effects so far!Bewitch
@JK, can you add an update to your question on how you implemented this? Did JSON.stringify came in play at any point?Hancock
@PavelRepin, I had to call JSON.stringify() on the payload.Kirchhoff
@Maziar - here are 3 solutions to "is there some way that I can change the behavior of $.post() to send contentType=application/json?". What part is not an answer?Exegete
It's also important to know: $.ajax and it's various methods will attempt to guess what the contentType should be (unless it's specified) based on the data you give it. "mystring data" will be application/x-www-form-urlencoded; where as an object { anyKey: "anyvalue and type" } will be application/json. Many servers that read json, will only allow an object or array, not a string--thus why jquery predicts things this way. If you have a server that reads strings, numbers, etc without being wrapped in an object, you must specify the content-type as in this answer.Falange
I
428
$.ajax({
  url:         url,
  type:        "POST",
  data:        JSON.stringify(data),
  contentType: "application/json; charset=utf-8",
  dataType:    "json",
  success:     function(){
    ...
  }
})

See : jQuery.ajax()

Iverson answered 16/5, 2010 at 21:9 Comment(8)
The original post asks : "So is there some way that I can change the behavior of $.post() to send contentType=application/json?" BUT it also states "That works but affects every single $.get and $.post that I have and causes some to break.". I understand the question as "how can I achieve the same thing as using $.post but sending the right contentType without breaking the other occurrences of $.get and $.post". Is that incorrect ?Iverson
@x1a4 clearly doesn't understand that .ajax is the call, not ajaxSetupKohn
@Adrien, for what it's worth two years later, yours is the answer I was looking for when I googled this.Syzran
@Iverson = same here. v usefulProudman
had to use JSON.stringify(data), since server expects a JSON string and jQuery would simply concatenate the key-value pairs using ampersands, form-urlencoded.Maziar
Even four years later, this answer has solved my hours of searching with less than ten lines of code.Capsulate
Since jQuery v1.9 { ... type: "POST" ... } must be replaced by { ... method: "POST" ... }Handwoven
@Maziar This is genius, you should update the answer because the default answer doesn't make true POST ;)Everard
M
106

Finally I found the solution, that works for me:

jQuery.ajax ({
    url: myurl,
    type: "POST",
    data: JSON.stringify({data:"test"}),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function(){
        //
    }
});
Mikvah answered 26/1, 2012 at 14:46 Comment(5)
Couldn't figure out why I kept getting errors, turns out you have to stringify the data.Sighted
I know this works, but WHY oh WHY do you need to stringify? Is it a jQuery bug? It seems to be perfectly happy to serialize your data argument to x-www-form-urlencoded, but if you indicate that the request content type is JSON, it still insists on sending data in a mismatched format.Hancock
Well. I did not dig it much. I was happy it was working. ;) My server requires JSON.Mikvah
Same here. Without JSON.stringify it does not work, I wonder why.Armes
JSON.stringify() saved me. +1Spunk
E
77

I think you may have to

1.Modify the source to make $.post always use JSON data type as it really is just a shortcut for a pre configured $.ajax call

Or

2.Define your own utility function that is a shortcut for the $.ajax configuration you want to use

Or

3.You could overwrite the $.post function with your own implementation via monkey patching.

The JSON datatype in your example refers to the datatype returned from the server and not the format sent to the server.

Exegete answered 16/5, 2010 at 21:5 Comment(7)
+1, I would go for defining a new method, or overwriting jQuery.post method, it's a really simple function...Pierides
Its not a bad idea, just create a method called $.mvcpost() that does the same as $.post (by copying the linked code) plus changes the contenttype. Then for all the $.post()s that need to be changed, I just have to type 3 extra characters in front. Its much quicker than rewriting them as $.ajax().Bewitch
I have implemented this and its working well. No side effects so far!Bewitch
@JK, can you add an update to your question on how you implemented this? Did JSON.stringify came in play at any point?Hancock
@PavelRepin, I had to call JSON.stringify() on the payload.Kirchhoff
@Maziar - here are 3 solutions to "is there some way that I can change the behavior of $.post() to send contentType=application/json?". What part is not an answer?Exegete
It's also important to know: $.ajax and it's various methods will attempt to guess what the contentType should be (unless it's specified) based on the data you give it. "mystring data" will be application/x-www-form-urlencoded; where as an object { anyKey: "anyvalue and type" } will be application/json. Many servers that read json, will only allow an object or array, not a string--thus why jquery predicts things this way. If you have a server that reads strings, numbers, etc without being wrapped in an object, you must specify the content-type as in this answer.Falange
F
48

I ended up adding the following method to jQuery in my 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
    });
};

And to use it

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

This was done by simply copying the code of "get" and "post" from the original JQuery sources and hardcoding a few parameters to force a JSON POST.

Thanks!

Fults answered 26/6, 2013 at 8:1 Comment(3)
As usual - best answer comes last to the party and has least upvotes ;(Overseas
Great answer - takes a while to realise that $.post doesn't do this "out of the box".Hardtop
Still needs JSON.stringify around data for me.Virga
E
27

use just

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

UPDATED @JK: If you write in your question only one code example with $.post you find one corresponding example in the answer. I don't want to repeat the same information which you already studied till know: $.post and $.get are short forms of $.ajax. So just use $.ajax and you can use the full set of it's parameters without having to change any global settings.

By the way I wouldn't recommend overwriting the standard $.post. It's my personal opinion, but for me it's important, not only that the program works, but also that all who read your program understand it with the same way. Overwriting standard methods without having a very important reason can follow to misunderstanding in reading of the program code. So I repeat my recommendation one more time: just use the original $.ajax form jQuery instead of jQuery.get and jQuery.post and you receive programs which not only perfectly work, but can be read by people without any misunderstandings.

Enmity answered 16/5, 2010 at 21:7 Comment(1)
Great explanation and guidelineMchale
O
17

Guess what? @BenCreasy was totally right!!

Starting version 1.12.0 of jQuery we can do this:

$.post({
    url: yourURL,
    data: yourData,
    contentType: 'application/json; charset=utf-8'
})
    .done(function (response) {
        //Do something on success response...
    });

I just tested it and it worked!!

Overmodest answered 26/7, 2020 at 10:40 Comment(0)
T
10

This simple jquery API extention (from: https://benjamin-schweizer.de/jquerypostjson.html) for $.postJSON() does the trick. You can use postJSON() like every other native jquery Ajax call. You can attach event handlers and so on.

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

Like other Ajax APIs (like $http from AngularJS) it sets the correct contentType to application/json. You can pass your json data (javascript objects) directly, since it gets stringified here. The expected returned dataType is set to JSON. You can attach jquery's default event handlers for promises, for example:

$.postJSON(apiURL, jsonData)
 .fail(function(res) {
   console.error(res.responseText);
 })
 .always(function() {
   console.log("FINISHED ajax post, hide the loading throbber");
 });
Tole answered 18/4, 2018 at 5:40 Comment(0)
S
9

The "json" datatype that you can pass as the last parameter to post() indicates what type of data the function is expecting in the server's response, not what type it's sending in the request. Specifically it sets the "Accept" header.

Honestly your best bet is to switch to an ajax() call. The post() function is meant as a convenience; a simplified version of the ajax() call for when you are just doing a simple form posting. You aren't.

If you really don't want to switch, you could make your own function called, say, xpost(), and have it simply transform the given parameters into parameters for a jQuery ajax() call, with the content-type set. That way, rather than rewriting all of those post() functions into ajax() functions, you just have to change them all from post to xpost (or whatever).

Sultanate answered 16/5, 2010 at 21:14 Comment(1)
Its only the $.post() methods that call an asp.net mvc controller method that need to change. The pure jquery ones should be unchanged (autocomplete, diaplog, jqgrid etc) I was hoping there would a simple change that I could make to the relevant $.post()s. But it does look like I need to convert them to $.ajax(). Its a large and very ajax heavy app, so there are a lot of them to change.Bewitch
M
6

I know this is a late answer, I actually have a shortcut method that I use for posting/reading to/from MS based services.. it works with MVC as well as ASMX etc...

Use:

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

NOTE: I also have a JSON.parseAjax method that is modified from json.org's JS file, that adds handling for the MS "/Date(...)/" dates...

The modified json2.js file isn't included, it uses the script based parser in the case of IE8, as there are instances where the native parser breaks when you extend the prototype of array and/or object, etc.

I've been considering revamping this code to implement the promises interfaces, but it's worked really well for me.

Makings answered 27/3, 2012 at 23:24 Comment(0)
B
6

At the heart of the matter is the fact that JQuery at the time of writing does not have a postJSON method while getJSON exists and does the right thing.

a postJSON method would do the following:

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

and can be used like this:

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
    });
Bitner answered 22/5, 2014 at 19:22 Comment(1)
Beware! As its name implies getJSON only returns data in JSON format but that doesn't mean it sends data in the same format. Sure, it works as expected in ASP.Net MVC and with ASP.Net API, but try to use it in a WebMethod (ASP.Net WebForms) with the [ScriptMethod(UseHttpGet = true)] attribute and you'll be surprisedOvermodest
I
3

The documentation currently shows that as of 3.0, $.post will accept the settings object, meaning that you can use the $.ajax options. 3.0 is not released yet and on the commit they're talking about hiding the reference to it in the docs, but look for it in the future!

Inamorato answered 13/3, 2015 at 1:43 Comment(0)
P
2

I had a similar issue with the following JavaScript code:

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

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

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

Where in the Fiddler I could see the request with:

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

As a result, my server couldn't map an object to a server-side type.

After changing the last line to this one:

$.post(url, rating, showSavedNotification);

In the Fiddler I could still see:

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

However, the server started returning what I expected.

Pennyweight answered 20/11, 2016 at 23:20 Comment(0)
W
1

How about your own adapter/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;
    }
  }
})();

And extremely simple usage:

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... }
});
Woolard answered 28/8, 2014 at 9:47 Comment(1)
Tried but still not getting expected results. i have Spring Boot Rest API.Wenn
S
1

For some reason, setting the content type on the ajax request as @Adrien suggested didn't work in my case. However, you actually can change content type using $.post by doing this before:

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

Then make your $.post call:

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

I had trouble with jQuery + IIS, and this was the only solution that helped jQuery understand to use windows-1252 encoding for ajax requests.

Samadhi answered 27/2, 2018 at 11:6 Comment(0)
M
1

we can change Content-type like this in $.post

$.post(url,data, function (data, status, xhr) {
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");});
Marieann answered 16/8, 2018 at 2:2 Comment(1)
I tried this but unfortunately it didn't work for me. What did work was including this $.ajaxSetup({ contentType: "application/json; charset=utf-8" }); before the $.post callOvermodest
M
1

$.post does not work if you have CORS (Cross Origin Resource Sharing) issue. Try to use $.ajax in following format:

$.ajax({
        url: someurl,
        contentType: 'application/json',
        data: requestInJSONFormat,
        headers: { 'Access-Control-Allow-Origin': '*' },
        dataType: 'json',
        type: 'POST',
        async: false,
        success: function (Data) {...}
});
Megaton answered 5/3, 2019 at 4:20 Comment(0)
T
-20

You can't send application/json directly -- it has to be a parameter of a GET/POST request.

So something like

$.post(url, {json: "...json..."}, function());
Tragopan answered 16/5, 2010 at 21:6 Comment(1)
This answer may be incorrect, but it's not low quality, and it is an attempt to answer the question. From Review.Foretopsail

© 2022 - 2024 — McMap. All rights reserved.