Cannot set content-type to 'application/json' in jQuery.ajax
Asked Answered
B

11

121

When I have this code

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

in Fiddler I can see following raw request

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

But what I'm trying is to set content-type from application/x-www-form-urlencoded to application/json. But this code

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

Generates strange request (which I can see in 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

Why is that? What is OPTIONS when it should be POST there? And where is my content-type set to application/json? And request parameters has gone for some reason.

UPDATE 1

On server side I have really simple RESTful service.

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

But for some reason I can't call this method with parameters.

UPDATE 2

Sorry for not answering so long.

I've added these headers to my server response

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

It didn't help, I have Method not allowed error from server.

Here is what my fiddler says

enter image description here

So, now I can be sure that my server accepts POST, GET, OPTIONS (if response headers work like I expect). But why "Method not allowed"?

In WebView response from server (you can see Raw response on picture above) looks like this

enter image description here

Behl answered 17/3, 2012 at 23:39 Comment(8)
you should try JSON.stringfy() methodDrink
Look here. This works for me very well: #9755267Mining
I'm having the exact same issue, but i'm working with NodeJS as the backend, also i set all OPTION requests not only to be accepted but to force a 200 response on all OPTION requests so the rest of the petitions work as expected with no response...Tilla
Hi @VitaliiKorsakov. Have you solved your problem? I meet the same problem, i.e. cannot modify contentType.Orlantha
@Orlantha No, I was waiting for to long and this question become non-actual.Behl
Same problem. Need some help.Rhaetian
I had the same problem and just got it working.. the solution is in the answer on this page: #20295580 ..to sum it up: "When using contentType: 'application/json' you will not be able to rely on $_POST being populated. $_POST is only populated for form-encoded content types. As such, you need to read your data from PHP raw input".. I see now you are not using php on the server side but hopefully this information helps in some way.Pleasance
@Vitalii Korsakov: What fiddler do you use?Fulcrum
H
106

It would seem that removing http:// from the URL option ensures the the correct HTTP POST header is sent.

I don't think you need to fully qualify the name of the host, just use a relative URL as below.

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

An example of mine that works:

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

Possibly related: jQuery $.ajax(), $.post sending "OPTIONS" as REQUEST_METHOD in Firefox

After some more research I found out the OPTIONS header is used to find out if the request from the originating domain is allowed. Using fiddler, I added the following to the response headers from my server.

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

Once the browser received this response it then sent off the correct POST request with JSON data. It would seem that the default form-urlencoded content type is considered safe and so does not undergo the extra cross domain checks.

It looks like you will need to add the previously mentioned headers to your servers response to the OPTIONS request. You should of course configure them to allow requests from specific domains rather then all.

I used the following jQuery to test this.

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

References:

Harakiri answered 18/3, 2012 at 12:36 Comment(8)
I want to loose coupling between client and server. Server is RESTful service and all clients of this service should know url to it.Behl
Can you provide some more details in your post about the scenario of this question? If your clients are going to be on different domains, you might encounter same origin issues.Harakiri
I've posted additional info about server side. Right now server and client both on localhost but differ in port. Later they most likely will be on different domains.Behl
It seems like the issue you are experiencing is to do with same origin policy, it might be worth looking at jsonp and the question I linked to in my answer in addition to these links - related question. jquery cross domain guide - I dont have much experience with cross domain requests but hopefully those links will be of use to you.Harakiri
I don't think that this is a problem because everything works fine when I don't pass any parameters and content-type is application/x-www-form-urlencoded. But I don't need POST request if I couldn't pass any parameters.Behl
@Spike +1 for the info on the preflight. This answer should be accepted IMHO.Gutshall
Please, see "Update 2" in my post. @RayToal I can not accept this answer since it does not work for me.Behl
It was JSON.stringify() that did it for me - have been working on this issue for a while now, lucky I picked that out of your working example! Without that function my request was malformed - not sure why, tried every possible variation of json syntax, only that did the trick.Uncial
D
45

I can show you how I used it

  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;
                }
            }
        });
    }
Drink answered 18/3, 2012 at 12:34 Comment(4)
The same thing as in next answer. I can't not to specify url to server where all service functions are hostedBehl
@VitaliiKorsakov i went away, have you sort out your problem.Drink
Thanks for the answer! I can't believe this isn't spelled out somewhere else. It sure seems like JQuery would post json when the type you specify is 'json', but I guess not...Linguistician
@JasonGoemaat the dataType parameter in jQuery is only used to parse the returned response body. If you read the documentation, you'll see that it's not even needed. The default value for dataType is intelligent guess. Your problem is that the data attribute in jquery isn't configurable. You can't tell how jquery should parse the data object. That's why you have to serialize json before. Because jquery only serialize to url-form-encodeQuietus
L
12

So all you need to do for this to work is add:

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

as a field to your post request and it'll work.

Lantern answered 19/1, 2016 at 18:53 Comment(2)
api.jquery.com/jquery.ajax If you look in the documentation it says that without specifying it defaults to 'application/x-www-form-urlencoded; charset=UTF-8' (which is why that's happening. Idk why just setting contentType doesn't work though. You might want to check what version of jQuery you have and update if you're on an old version).Lantern
This is not working. Even though I have type: "POST", it is sending OPTIONS.Underpinning
F
7

If you use this:

contentType: "application/json"

AJAX won't sent GET or POST params to the server.... don't know why.

It took me hours to lear it today.

Just Use:

$.ajax(
  { url : 'http://blabla.example/wsGetReport.php',
    data : myFormData, type : 'POST', dataType : 'json',
    // contentType: "application/json",
    success : function(wsQuery) { }
  }
)
Fortuneteller answered 4/3, 2017 at 0:55 Comment(1)
sadly the correct answer for me. Omit contentType and just use dataType to bypass CORS OPTIONS garbage that many services just don't implement properly. So annoying.Boohoo
M
5

I recognized those screens, I'm using CodeFluentEntities, and I've got solution that worked for me as well.

I'm using that construction:

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

as you can see, if I use

contentType: "",

or

contentType: "text/plain", //chrome

Everything works fine.

I'm not 100% sure that it's all that you need, cause I've also changed headers.

Misapprehend answered 27/2, 2015 at 7:15 Comment(0)
P
3

I was fighting this same issue and it was caused by a lack of JSON.stringfy() i.e.

data: JSON.stringfy({ name: 'norm' }),

Hope this saves someone else a lot of time!

Pandemonium answered 20/5, 2021 at 14:27 Comment(0)
M
2

I found the solution for this problem here. Don't forget to allow verb OPTIONS on IIS app service handler.

Works fine. Thank you André Pedroso. :-)

Mining answered 11/9, 2013 at 11:34 Comment(1)
Please don't post link-only answers. This link is behind a login wall. Include the relevant information in the post itself. There's no need to say "Thanks" in posts.Tedra
R
1

I had the same issue. I'm running a java rest app on a jboss server. But I think the solution is similar on an ASP .NET webapp.

Firefox makes a pre call to your server / rest url to check which options are allowed. That is the "OPTIONS" request which your server doesn't reply to accordingly. If this OPTIONS call is replied correct a second call is performed which is the actual "POST" request with json content.

This only happens when performing a cross-domain call. In your case calling 'http://localhost:16329/Hello' instead of calling a url path under the same domain '/Hello'

If you intend to make a cross domain call you have to enhance your rest service class with an annotated method the supports a "OPTIONS" http request. This is the according java implementation:

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

So I guess in .NET you have to add an additional method annotated with

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

where the following headers are set

.header("Access-Control-Allow-Origin", "*")
        .header("Access-Control-Allow-Headers", "Content-Type")
        .header("Access-Control-Allow-Methods", "POST, OPTIONS")
Rehearing answered 9/12, 2014 at 16:7 Comment(0)
I
0

I got the solution to send the JSON data by POST request through jquery ajax. I used below code

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


        });
    });

I used 'Content-Type': 'text/plain' in header to send the raw json data.
Because if we use Content-Type: 'application/json' the request methods converted to OPTION, but using Content-Type: 'test/plain' the method does not get converted and remain as POST. Hopefully this will help some one.

Ics answered 28/3, 2018 at 8:36 Comment(1)
It's not really converting to OPTION, it's sending a CORS preflight request to check to see if the POST is permitted. When this doesn't come back right, the POST doesn't happen.Boohoo
L
0

Hi These two lines worked for me.

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

Thanks, Prashant

Legnica answered 4/6, 2020 at 11:22 Comment(0)
T
0

In the jQuery.ajax documentation, contentType specifies the type of content to send to the server. The default value is "application/x-www-form-urlencoded; charset=UTF-8". For cross-domain requests, if a content type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain is set, the OPTIONS method will be sent in the request header. It is a check that ajax does by the CORS policies to check if the methods that you request to the server (in this case POST) in your domain, are allowed If the OPTIONS method on your server where the API is hosted is allowed, the request you made to the server initially is made, in this case the POST is sent.

If you are making the request to the same domain and same port, the OPTIONS method is not sent. If this is the case, one of the solutions is to use "http://localhost:<port>..." or just use relative paths where you are going to make the request.

But if the REST API in your backend is in another domain, so there are two solutions.

  1. Do not put in ajax contentType: "application/json", and send the data either in JSON format as an Object or as a string, or a string with the parameters to send type key=value.
  2. Enable CORS in your Rest API (that is, allow OPTIONS, POST methods, for any domain, or your domain where you make the request).

The problem is that in some cases it is necessary to set the type of content to send as "application/json", because the server where the API is hosted does not accept other types of content.

If you have control over the BackEnd and the REST API, I recommend enabling CORS on it. (Also applies if it is the same domain but different port).

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

Or also allow other types of content like application/x-www-form-urlencoded or encode it in such a way that it also accepts strings with key=value parameters. This prevents jQuery from sending OPTIONS in its request header.

One last thing: if contentType: "application/json" is used and the server expects "application/json" as well, you should use JSON.stringify() on data, since when sending the request to the server, it seems to take the JSON as a string and not as an object. In my case, not using JSON.stringify() and using contentType: "application/json", returned me a server error with status 500

Taeniasis answered 8/9, 2022 at 4:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.