Cross domain XHR failing

2019-01-26 12:09发布

问题:

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?

回答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/).



回答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;

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



回答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.