Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A CORS POST request works from plain JavaScript, but why not with jQuery?

I'm trying to make a Cross Origin post request, and I got it working in plain JavaScript like this:

var request = new XMLHttpRequest(); var params = "action=something"; request.open('POST', url, true); request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");}; request.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); request.setRequestHeader("Content-length", params.length); request.setRequestHeader("Connection", "close"); request.send(params); 

But I would like to use jQuery, but I can't get it to work. This is what I'm trying:

$.ajax(url, {     type:"POST",     dataType:"json",     data:{action:"something"},      success:function(data, textStatus, jqXHR) {alert("success");},     error: function(jqXHR, textStatus, errorThrown) {alert("failure");} }); 

This results in Failure. If anyone knows why jQuery doesn't work, please let us all know. Thanks.

(I'm using jQuery 1.5.1, and Firefox 4.0, and my server is responding with a proper Access-Control-Allow-Origin header)

like image 619
Magmatic Avatar asked Apr 07 '11 17:04

Magmatic


People also ask

Does CORS only apply to JavaScript?

CORS is applied to requests when an Origin header is included in the request. This includes requests made from JavaScript and POST requests. It's not applied all resources.

Does CORS apply to POST?

Any CORS request has to be preflighted if: Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.

Can JavaScript send POST request?

To send a POST request using vanilla JavaScript, you can use an XMLHttpRequest object to interact with the server and provide the correct Content-Type request header for the POST message body data.


2 Answers

UPDATE: As TimK pointed out, this isn't needed with jquery 1.5.2 any more. But if you want to add custom headers or allow the use of credentials (username, password, or cookies, etc), read on.


I think I found the answer! (4 hours and a lot of cursing later)

//This does not work!! Access-Control-Allow-Headers: * 

You need to manually specify all the headers you will accept (at least that was the case for me in FF 4.0 & Chrome 10.0.648.204).

jQuery's $.ajax method sends the "x-requested-with" header for all cross domain requests (i think its only cross domain).

So the missing header needed to respond to the OPTIONS request is:

//no longer needed as of jquery 1.5.2 Access-Control-Allow-Headers: x-requested-with 

If you are passing any non "simple" headers, you will need to include them in your list (i send one more):

//only need part of this for my custom header Access-Control-Allow-Headers: x-requested-with, x-requested-by 

So to put it all together, here is my PHP:

// * wont work in FF w/ Allow-Credentials //if you dont need Allow-Credentials, * seems to work header('Access-Control-Allow-Origin: http://www.example.com'); //if you need cookies or login etc header('Access-Control-Allow-Credentials: true'); if ($this->getRequestMethod() == 'OPTIONS') {   header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');   header('Access-Control-Max-Age: 604800');   //if you need special headers   header('Access-Control-Allow-Headers: x-requested-with');   exit(0); } 
like image 151
Will Mason Avatar answered Oct 22 '22 01:10

Will Mason


Another possibility is that setting dataType: json causes JQuery to send the Content-Type: application/json header. This is considered a non-standard header by CORS, and requires a CORS preflight request. So a few things to try:

1) Try configuring your server to send the proper preflight responses. This will be in the form of additional headers like Access-Control-Allow-Methods and Access-Control-Allow-Headers.

2) Drop the dataType: json setting. JQuery should request Content-Type: application/x-www-form-urlencoded by default, but just to be sure, you can replace dataType: json with contentType: 'application/x-www-form-urlencoded'

like image 39
monsur Avatar answered Oct 22 '22 01:10

monsur