Cross domain XHR failing

21,739

Solution 1

The server should also reply to the preflight with the following header:

Access-Control-Allow-Headers: Content-Type

This is necessary because the content type is application/json, which is outside the acceptable values defined in the CORS spec (http://www.w3.org/TR/cors/).

Solution 2

Your sever setup works. JSFiddle apparently does not make the ajax requests, but you can quickly test that it works by entering these four lines into Chrome console or Safari developer console:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://projectwhatup.us:5000/api/posts', false);
xhr.send();
xhr.responseText;

enter image description here

If you try this with a domain that does not allow CORS, it will error out.

Solution 3

The reason that adding a 'Content-Type' header makes your CORS request fail is because your server is set up wrongly.

If the client wishes to specify particular headers or use an unusual http method verb (e.g. PUT), then the browser will first do a 'preflight' OPTIONS call to ensure that it is allowed to set those headers. Your server needs to respond to this OPTIONS call with the appropriate headers. You'll see that options call in the network tab of the Chrome developer tools or firebug if you want to confirm that this is what the problem is.

You may be interested in my more detailed answer here.

Share:
21,739
Ayush
Author by

Ayush

I have a keen interest in the Language Development stack (Parsers, Lexers, ASTs, Compilers and VMs), Web development and Javascript frameworks (particularly AngularJS) along with security and cryptography. Lately been working on infrastructure and service monitoring, containers and Kubernetes.

Updated on July 09, 2022

Comments

  • Ayush
    Ayush almost 2 years

    I have an API hosted on one domain that has CORS enabled with the following headers:

    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Max-Age: 1728000
    

    I am able to make a GET or POST request from hackst.com and it works fine. Link: http://hackst.com/#w3SbV

    From my backbone app hosted on another domain, GET requests work fine. But when I try to create and save a new model (i.e. make a POST request), it fails with the following error:

    Failed to load resource: the server responded with a status of 501 (Not Implemented) http://projectwhatup.us:5000/api/posts
    XMLHttpRequest cannot load http://projectwhatup.us:5000/api/posts. Origin http://ayush.projectwhatup.us is not allowed by Access-Control-Allow-Origin.
    

    My relevant backbone code:

    var newPostData = {
        topic : "New Post",
        body : "new body",          
        user_id : 1,
    };  
    
    var newPostModel = new Post(newPostData);
    this.model.create(newPostModel);
    

    I even tried over-riding the create method and making a POST request manually like this:

    create : function(data) {
        console.log('overriden create');
    
        $.ajax({
            "url" : this.url,
            "async" : true,
            "beforeSend" : function(obj){
                console.log(obj);
            },
            "contentType" : 'application/json',
            //"crossDomain" : true,  // uncommenting this doesnt help either
            "headers" : {
    
            },
            "dataType" : 'json',
            "type" : 'POST',
            "data" : JSON.stringify(data),
            "error" : function(err){
                console.log('new post creation failed');
                console.log(err);
            },
            "success" : function(resp){
                console.log('new post created');
                console.log(resp);
            }
        });
    }
    

    Same error.

    I tried a stand-alone GET request on JSFiddle as well (http://jsfiddle.net/X9cqh/5/), but that fails even though my backbone app can make the GET request fine.

    I'm completely clueless at this point. Any hints, pointers, solutions?