尽管标头正确,但 CORS Access-Control-Allow-Origin

Posted

技术标签:

【中文标题】尽管标头正确,但 CORS Access-Control-Allow-Origin【英文标题】:CORS Access-Control-Allow-Origin despite correct headers 【发布时间】:2012-03-25 16:09:39 【问题描述】:

我正在尝试在客户端上使用 jQuery (1.7.1) 驱动的 ajax 和 apache 服务的 python (django) 服务器来设置简单的跨域资源共享。根据我已阅读的所有说明,我的标题设置正确,但我不断收到以下错误:

XMLHttpRequest 无法加载 http://myexternaldomain.com/get_data。 来源http://localhost:8080 不允许 访问控制允许来源。

我正在尝试发送的标题(我不确定它是否能通过浏览器)发送是:

Request URL:http://myexternaldomain.com/get_data
Accept:application/json, text/javascript, */*; q=0.01
Origin:http://localhost:8080
Referer:http://localhost:8080/static/js/test-zetta.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11

javascript代码是

    var request = $.ajax(
        url : "http://myexternaldomain.com/get_data",
        type : "POST",
        dataType : "json",
        crossDomain : true
    );

注意origin 设置正确。服务器使用以下python代码添加标头Access-Control-Allow-Origin = *

def process_response(self, response):
    if response.has_header('Access-Control-Allow-Origin'):
            return response

    response['Access-Control-Allow-Origin'] = '*'
    return response

def get_orders(request):
    """ Tell worker what to do """
    response_data = 
    response_data['action'] = 'probe'
    response = process_response(HttpResponse(json.dumps(response_data), mimetype="application/json"))
    return response

如果我直接访问该地址,似乎可以确认标题设置正确

Access-Control-Allow-Origin:*
Content-Type:application/json
Date:Thu, 08 Mar 2012 05:06:25 GMT
Server:Apache/2.2.20 (Ubuntu)
Transfer-Encoding:chunked

但是在跨域设置中它总是失败(尝试了 chrome 和 firefox)。我已经尝试完全按照this 问题的选定答案来实现代码,但是得到了同样的错误

更新

我很确定问题出在服务器端,因为我已经设法让我的 ajax 调用与另一个启用了 CORS 的公共服务器一起工作。当我比较从该公共服务器返回的标头和从我返回的标头(当我从同一域进行测试时)时,我看不出任何可能导致差异的主要差异(见下文)。

我排除的一个微妙之处可能很重要,也可能很重要,那就是实际域是多个子域的亚马逊域。 真实地址是http://ec2-23-20-27-108.compute-1.amazonaws.com/get_orders,请随意探查,看看我做错了什么。

来自公共服务器

Access-Control-Allow-Origin:*
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:622
Content-Type:text/html
Date:Thu, 08 Mar 2012 15:33:20 GMT
Keep-Alive:timeout=15, max=99
Server:Apache/2.2.14 (Ubuntu)
Vary:Accept-Encoding
X-Powered-By:Perl/5.8.7, php/4.4.0

来自我的服务器 - (不能跨域工作)

Access-Control-Allow-Origin:*
Content-Encoding:gzip
Content-Type:text/plain
Date:Thu, 08 Mar 2012 15:32:24 GMT
Server:Apache/2.2.20 (Ubuntu)
Transfer-Encoding:chunked
Vary:Accept-Encoding

【问题讨论】:

我过去曾尝试为 Json 数据启用 CORS,但从未成功。 CORS 可能会像那样不稳定。最好只返回 JSON-P。 您只是发布来自远程服务器和本地客户端之间的 final 交换的标头。如果您查看完整的交换,我相信您会看到一个 OPTIONS 请求以及包含 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 标头的响应。 【参考方案1】:

我在使用出色的 django-cors-headers 库时也遇到了这个问题。对我来说,解决方案是将“接受编码”添加到默认的 CORS_ALLOW_HEADERS 元组中。

【讨论】:

【参考方案2】:

您必须实现“预发送”请求和响应,因为您的情况算作“not so simple”请求。仅需要 Origin 标头的基本 CORS 只能具有“application/x-www-form-urlencoded”、“multipart/form-data”和“text/plain”的内容类型。由于您返回“application/json”,因此您不满足此要求。

我对 Django 一无所知,但我发现通过使用Tomcat filter 在我的应用程序之外实现 CORS 支持更容易。看起来你可以用 Django 来do the same thing。

2013-08-11: 看起来 GitHub 存储库已不在我们身边。但是 Django 包看起来仍然可以在 https://pypi.python.org/pypi/django-cors/0.1

获得

【讨论】:

很确定浏览器应该处理预检请求....至少 Chrome 可以。 但服务器必须识别它。他的脚本仅通过在每个请求中添加 Origin 标头来响应基本请求。 我尝试使请求变得简单,方法是让我的数据成为一个简单的字符串,在 $.ajax 调用中期望纯文本并在 python 中返回 mimetype='text/plain',但仍然得到相同错误。 我还设法使它与启用了公共 cors 的服务器一起工作,因此可以确信我的问题出在服务器端。 我不能夸大这个答案的真棒。它已经死了。【参考方案3】:

所以我被转到 URL 的响应误导了,实际上问题是在执行 ajax 请求时,由于 csrf 保护,我收到了 403(仅在 firefox 而不是 chrome 中显示)错误。

【讨论】:

天哪,非常感谢。我的enable_cors 包装器围绕着我的csrf_exempt 包装器,需要反转它们。我当时想,WTF...

以上是关于尽管标头正确,但 CORS Access-Control-Allow-Origin的主要内容,如果未能解决你的问题,请参考以下文章

尽管端点在 apicontroller 内部的行为中使用了 cors 类,但 CORS 标头未添加到响应中

尽管设置了标头,但 CORS 不起作用

尽管在 Flask 中设置了响应标头,但 CORS 错误

尽管预检响应中有 Access-Control-Allow-Origin 标头,但 CORS 错误

带有 PHP 标头的跨域请求标头 (CORS)

尽管设置了标头,但不允许 CORS 请求