[jquery] How to get a cross-origin resource sharing (CORS) post request working

I have a machine on my local lan (machineA) that has two web servers. The first is the in-built one in XBMC (on port 8080) and displays our library. The second server is a CherryPy python script (port 8081) that I am using to trigger a file conversion on demand. The file conversion is triggered by a AJAX POST request from the page served from the XBMC server.

  • Goto http://machineA:8080 which displays library
  • Library is displayed
  • User clicks on 'convert' link which issues the following command -

jQuery Ajax Request

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • The browser issues a HTTP OPTIONS request with the following headers;

Request Header - OPTIONS

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: http://machineA:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-requested-with
  • The server responds with the following;

Response Header - OPTIONS (STATUS = 200 OK)

Content-Length: 0
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:40:29 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: text/html;charset=ISO-8859-1
  • The conversation then stops. The browser, should in theory, issue a POST request as the server responded with the correct (?) CORS headers (Access-Control-Allow-Origin: *)

For troubleshooting, I have also issued the same $.post command from http://jquery.com. This is where I am stumped, from jquery.com, the post request works, a OPTIONS request is sent following by a POST. The headers from this transaction are below;

Request Header - OPTIONS

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: http://jquery.com
Access-Control-Request-Method: POST

Response Header - OPTIONS (STATUS = 200 OK)

Content-Length: 0
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:37:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: text/html;charset=ISO-8859-1

Request Header - POST

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://jquery.com/
Content-Length: 12
Origin: http://jquery.com
Pragma: no-cache
Cache-Control: no-cache

Response Header - POST (STATUS = 200 OK)

Content-Length: 32
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:37:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: application/json

I can't work out why the same request would work from one site, but not the other. I am hoping someone might be able to point out what I am missing. Thanks for your help!

This question is related to jquery ajax cherrypy cors

The answer is


REQUEST:

 $.ajax({
            url: "http://localhost:8079/students/add/",
            type: "POST",
            crossDomain: true,
            data: JSON.stringify(somejson),
            dataType: "json",
            success: function (response) {
                var resp = JSON.parse(response)
                alert(resp.status);
            },
            error: function (xhr, status) {
                alert("error");
            }
        });

RESPONSE:

response = HttpResponse(json.dumps('{"status" : "success"}'))
response.__setitem__("Content-type", "application/json")
response.__setitem__("Access-Control-Allow-Origin", "*")

return response

This is a summary of what worked for me:

Define a new function (wrapped $.ajax to simplify):

jQuery.postCORS = function(url, data, func) {
  if(func == undefined) func = function(){};
  return $.ajax({
    type: 'POST', 
    url: url, 
    data: data, 
    dataType: 'json', 
    contentType: 'application/x-www-form-urlencoded', 
    xhrFields: { withCredentials: true }, 
    success: function(res) { func(res) }, 
    error: function() { 
            func({}) 
    }
  });
}

Usage:

$.postCORS("https://example.com/service.json",{ x : 1 },function(obj){
      if(obj.ok) {
           ...
      }
});

Also works with .done,.fail,etc:

$.postCORS("https://example.com/service.json",{ x : 1 }).done(function(obj){
      if(obj.ok) {
           ...
      }
}).fail(function(){
    alert("Error!");
});

Server side (in this case where example.com is hosted), set these headers (added some sample code in PHP):

header('Access-Control-Allow-Origin: https://not-example.com');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 604800');
header("Content-type: application/json");
$array = array("ok" => $_POST["x"]);
echo json_encode($array);

This is the only way I know to truly POST cross-domain from JS.

JSONP converts the POST into GET which may display sensitive information at server logs.


Using this in combination with Laravel solved my problem. Just add this header to your jquery request Access-Control-Request-Headers: x-requested-with and make sure that your server side response has this header set Access-Control-Allow-Headers: *.


Well I struggled with this issue for a couple of weeks.

The easiest, most compliant and non hacky way to do this is to probably use a provider JavaScript API which does not make browser based calls and can handle Cross Origin requests.

E.g. Facebook JavaScript API and Google JS API.

In case your API provider is not current and does not support Cross Origin Resource Origin '*' header in its response and does not have a JS api (Yes I am talking about you Yahoo ),you are struck with one of three options-

  1. Using jsonp in your requests which adds a callback function to your URL where you can handle your response. Caveat this will change the request URL so your API server must be equipped to handle the ?callback= at the end of the URL.

  2. Send the request to your API server which is controller by you and is either in the same domain as the client or has Cross Origin Resource Sharing enabled from where you can proxy the request to the 3rd party API server.

  3. Probably most useful in cases where you are making OAuth requests and need to handle user interaction Haha! window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')


I had the exact same issue where jquery ajax only gave me cors issues on post requests where get requests worked fine - I tired everything above with no results. I had the correct headers in my server etc. Changing over to use XMLHTTPRequest instead of jquery fixed my issue immediately. No matter which version of jquery I used it didn't fix it. Fetch also works without issues if you don't need backward browser compatibility.

        var xhr = new XMLHttpRequest()
        xhr.open('POST', 'https://mywebsite.com', true)
        xhr.withCredentials = true
        xhr.onreadystatechange = function() {
          if (xhr.readyState === 2) {// do something}
        }
        xhr.setRequestHeader('Content-Type', 'application/json')
        xhr.send(json)

Hopefully this helps anyone else with the same issues.


This is a little late to the party, but I have been struggling with this for a couple of days. It is possible and none of the answers I found here have worked. It's deceptively simple. Here's the .ajax call:

_x000D_
_x000D_
    <!DOCTYPE HTML>_x000D_
    <html>_x000D_
    <head>_x000D_
    <body>_x000D_
     <title>Javascript Test</title>_x000D_
     <script src="http://code.jquery.com/jquery-latest.min.js"></script>_x000D_
     <script type="text/javascript">_x000D_
     $(document).domain = 'XXX.com';_x000D_
     $(document).ready(function () {_x000D_
     $.ajax({_x000D_
        xhrFields: {cors: false},_x000D_
        type: "GET",_x000D_
        url: "http://XXXX.com/test.php?email='[email protected]'",_x000D_
        success: function (data) {_x000D_
           alert(data);_x000D_
        },_x000D_
        error: function (x, y, z) {_x000D_
           alert(x.responseText + " :EEE: " + x.status);_x000D_
        }_x000D_
    });_x000D_
    });_x000D_
    </script> _x000D_
    </body>_x000D_
    </html>
_x000D_
_x000D_
_x000D_

Here's the php on the server side:

_x000D_
_x000D_
    <html>_x000D_
    <head>_x000D_
     <title>PHP Test</title>_x000D_
     </head>_x000D_
    <body>_x000D_
      <?php_x000D_
      header('Origin: xxx.com');_x000D_
      header('Access-Control-Allow-Origin:*');_x000D_
      $servername = "sqlxxx";_x000D_
      $username = "xxxx";_x000D_
      $password = "sss";_x000D_
      $conn = new mysqli($servername, $username, $password);_x000D_
      if ($conn->connect_error) {_x000D_
        die( "Connection failed: " . $conn->connect_error);_x000D_
      }_x000D_
      $sql = "SELECT email, status, userdata  FROM msi.usersLive";_x000D_
      $result = $conn->query($sql);_x000D_
      if ($result->num_rows > 0) {_x000D_
      while($row = $result->fetch_assoc()) {_x000D_
        echo $row["email"] . ":" . $row["status"] . ":" . $row["userdata"] .  "<br>";_x000D_
      }_x000D_
    } else {_x000D_
      echo "{ }";_x000D_
    }_x000D_
    $conn->close();_x000D_
    ?>_x000D_
    </body>
_x000D_
_x000D_
_x000D_


I solved my own problem when using google distance matrix API by setting my request header with Jquery ajax. take a look below.

var settings = {
          'cache': false,
          'dataType': "jsonp",
          "async": true,
          "crossDomain": true,
          "url": "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=place_id:"+me.originPlaceId+"&destinations=place_id:"+me.destinationPlaceId+"&region=ng&units=metric&key=mykey",
          "method": "GET",
          "headers": {
              "accept": "application/json",
              "Access-Control-Allow-Origin":"*"
          }
      }

      $.ajax(settings).done(function (response) {
          console.log(response);

      });

Note what i added at the settings
**

"headers": {
          "accept": "application/json",
          "Access-Control-Allow-Origin":"*"
      }

**
I hope this helps.


If for some reasons while trying to add headers or set control policy you're still getting nowhere you may consider using apache ProxyPass…

For example in one <VirtualHost> that uses SSL add the two following directives:

SSLProxyEngine On
ProxyPass /oauth https://remote.tld/oauth

Make sure the following apache modules are loaded (load them using a2enmod):

  • proxy
  • proxy_connect
  • proxy_http

Obviously you'll have to change your AJAX requests url in order to use the apache proxy…


Took me some time to find the solution.

In case your server response correctly and the request is the problem, you should add withCredentials: true to the xhrFields in the request:

$.ajax({
    url: url,
    type: method,
    // This is the important part
    xhrFields: {
        withCredentials: true
    },
    // This is the important part
    data: data,
    success: function (response) {
        // handle the response
    },
    error: function (xhr, status) {
        // handle errors
    }
});

Note: jQuery >= 1.5.1 is required


For some reason, a question about GET requests was merged with this one, so I'll respond to it here.

This simple function will asynchronously get an HTTP status reply from a CORS-enabled page. If you run it, you'll see that only a page with the proper headers returns a 200 status if accessed via XMLHttpRequest -- whether GET or POST is used. Nothing can be done on the client side to get around this except possibly using JSONP if you just need a json object.

The following can be easily modified to get the data held in the xmlHttpRequestObject object:

_x000D_
_x000D_
function checkCorsSource(source) {_x000D_
  var xmlHttpRequestObject;_x000D_
  if (window.XMLHttpRequest) {_x000D_
    xmlHttpRequestObject = new XMLHttpRequest();_x000D_
    if (xmlHttpRequestObject != null) {_x000D_
      var sUrl = "";_x000D_
      if (source == "google") {_x000D_
        var sUrl = "https://www.google.com";_x000D_
      } else {_x000D_
        var sUrl = "https://httpbin.org/get";_x000D_
      }_x000D_
      document.getElementById("txt1").innerHTML = "Request Sent...";_x000D_
      xmlHttpRequestObject.open("GET", sUrl, true);_x000D_
      xmlHttpRequestObject.onreadystatechange = function() {_x000D_
        if (xmlHttpRequestObject.readyState == 4 && xmlHttpRequestObject.status == 200) {_x000D_
          document.getElementById("txt1").innerHTML = "200 Response received!";_x000D_
        } else {_x000D_
          document.getElementById("txt1").innerHTML = "200 Response failed!";_x000D_
        }_x000D_
      }_x000D_
      xmlHttpRequestObject.send();_x000D_
    } else {_x000D_
      window.alert("Error creating XmlHttpRequest object. Client is not CORS enabled");_x000D_
    }_x000D_
  }_x000D_
}
_x000D_
<html>_x000D_
<head>_x000D_
  <title>Check if page is cors</title>_x000D_
</head>_x000D_
<body>_x000D_
  <p>A CORS-enabled source has one of the following HTTP headers:</p>_x000D_
  <ul>_x000D_
    <li>Access-Control-Allow-Headers: *</li>_x000D_
    <li>Access-Control-Allow-Headers: x-requested-with</li>_x000D_
  </ul>_x000D_
  <p>Click a button to see if the page allows CORS</p>_x000D_
  <form name="form1" action="" method="get">_x000D_
    <input type="button" name="btn1" value="Check Google Page" onClick="checkCorsSource('google')">_x000D_
    <input type="button" name="btn1" value="Check Cors Page" onClick="checkCorsSource('cors')">_x000D_
  </form>_x000D_
  <p id="txt1" />_x000D_
</body>_x000D_
</html>
_x000D_
_x000D_
_x000D_


Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to ajax

Getting all files in directory with ajax Cross-Origin Read Blocking (CORB) Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource Fetch API request timeout? How do I post form data with fetch api? Ajax LARAVEL 419 POST error Laravel 5.5 ajax call 419 (unknown status) How to allow CORS in react.js? Angular 2: How to access an HTTP response body? How to post a file from a form with Axios

Examples related to cherrypy

How to open a web server port on EC2 instance How to POST JSON data with Python Requests? How to get a cross-origin resource sharing (CORS) post request working

Examples related to cors

Axios having CORS issue Cross-Origin Read Blocking (CORB) Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource How to allow CORS in react.js? Set cookies for cross origin requests XMLHttpRequest blocked by CORS Policy How to enable CORS in ASP.net Core WebAPI No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API How to overcome the CORS issue in ReactJS Trying to use fetch and pass in mode: no-cors