跨域 XHR 失败

Posted

技术标签:

【中文标题】跨域 XHR 失败【英文标题】:Cross domain XHR failing 【发布时间】:2012-11-08 00:45:05 【问题描述】:

我有一个托管在一个域上的 API,该域启用了 CORS,并带有以下标头:

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

我可以从 hackst.com 发出 GET 或 POST 请求,并且工作正常。链接:http://hackst.com/#w3SbV

从我托管在另一个域上的主干应用程序中,GET 请求工作正常。但是当我尝试创建和保存新模型(即发出 POST 请求)时,它会失败并出现以下错误:

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.

我的相关主干代码:

var newPostData = 
    topic : "New Post",
    body : "new body",          
    user_id : 1,
;  

var newPostModel = new Post(newPostData);
this.model.create(newPostModel);

我什至尝试过覆盖 create 方法并像这样手动发出 POST 请求:

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

同样的错误。

我也在 JSFiddle (http://jsfiddle.net/X9cqh/5/) 上尝试了一个独立的 GET 请求,但是即使我的主干应用程序可以使 GET 请求正常,它也会失败。

在这一点上我完全一无所知。任何提示、指针、解决方案?

【问题讨论】:

查看hurl.it HEAD 对您的服务器的请求,似乎只为http://ayush.projectwhatup.us 启用了CORS 但是,来自 hackst.com 的请求是如何通过的? 这是因为您的网络浏览器没有发出请求。与 Hurl.it 类似,当您创建 hackst.com 请求时,它由后端的服务器执行,然后在您的网络浏览器中显示结果。 CORS 使一个网页能够直接在浏览器内访问另一个域的信息,例如 ajax 请求。在浏览器之外,任何人都可以随时向任何服务器发出 HTTP 请求。例如,您现在可以从任何计算机远程登录 80 到 projectwhatup.us,无论它们是否启用了 CORS。 啊!没想到 hurl 和 hackst 是通过后端发出请求的。 【参考方案1】:

您的服务器设置有效。 JSFiddle 显然不会发出 ajax 请求,但您可以通过在 Chrome 控制台或 Safari 开发者控制台中输入以下四行来快速测试它是否有效:

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

如果您在不允许 CORS 的域上尝试此操作,则会出错。

【讨论】:

发现在请求中添加 Content-Type: application/json 会导致 CORS 失败。没有它,ajax 调用将正常工作 (jsfiddle.net/X9cqh/11) 问题是在发出 POST 请求时,API 需要设置该标头,或者它以 400 Bad Request 响应 此答案中的代码不会触发预检(没有额外的标头并使用简单的方法 GET),这就是它看起来有效的原因。【参考方案2】:

服务器还应使用以下标头回复预检:

Access-Control-Allow-Headers: Content-Type

这是必要的,因为内容类型是 application/json,它超出了 CORS 规范 (http://www.w3.org/TR/cors/) 中定义的可接受值。

【讨论】:

我们已经向服务器添加了Access-Control-Allow-Headers: Content-TypeAccess-Control-Allow-Headers: Content-Type, X-Requested-With(或者,不是同时),但是在发出请求时指定content-type 会导致请求失败。 “非此即彼”是什么意思?您应该在标题中包含所有这些值。 哦,是的,伙计!我在这个麻烦上浪费了 2 天时间。谢谢! 这对我有用,遇到了同样的问题并且答案很有效,很多谢谢【参考方案3】:

添加“Content-Type”标头导致 CORS 请求失败的原因是您的服务器设置错误。

如果客户端希望指定特定的标头或使用不寻常的 http 方法动词(例如 PUT),则浏览器将首先执行“预检”OPTIONS 调用以确保允许设置这些标头。您的服务器需要使用适当的标头响应此 OPTIONS 调用。如果您想确认问题出在哪里,您会在 Chrome 开发人员工具或 firebug 的网络选项卡中看到选项调用。

你可能对我更详细的回答here感兴趣。

【讨论】:

以上是关于跨域 XHR 失败的主要内容,如果未能解决你的问题,请参考以下文章

layui跨域问题

XHR 加载失败:POST

XHR 请求在 Scrapy 中失败,但在 python-requests 中有效

Springboot ajax xhr 加载失败 404 错误

ajax请求成功或失败的参数

如果修改 XHR,则 JQuery AJAX 请求失败并出现 CORS 错误