跨域ajax OPTIONS错误403(Django)

时间:2016-07-04 14:42:56

标签: ajax django cookies cors cross-domain

我正在使用django开发一些网站aaa.com,它发送跨域ajax“GET”请求从bbb.com接收json数据,bbb.com也在django上运行并使用REST框架。在这一点上,添加crossDomain: true; withCredentials:true一切都很好。当然它在aaa.com的服务器端配置。
...-Allow-Credentials: true; ...-Allow-Origin: bbb.com

当aaa.com尝试发出PUT POST DELETE ajax请求时,主要问题就出现了。 根据CORS文档: [https://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0],客户端ajax请求正确,并且
...-Allow-Headers, ...-Allow-Methods

匹配 ...-Request-Headers, ...-Request-Methods

所以这个请求不是'简单',首先浏览器会从aaa.com向bbb.com发送预检请求,询问是否允许使用某些自定义标头和方法。

一切都很好但我仍然得到403错误。这是请求/回复:

General:
Request URL:http://bbb.com/api/someapipage/
Request Method:OPTIONS
Status Code:403 Forbidden
Remote Address:some ip:80

Response Headers:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:accept, content-type, x-csrftoken, x-requested-with
Access-Control-Allow-Methods:GET, POST, OPTIONS, HEAD, PUT, DELETE
Access-Control-Allow-Origin:http://aaa.com
Allow:GET, POST, HEAD, OPTIONS
Connection:Keep-Alive
Content-Language:en
Content-Type:application/json
Date:Mon, 04 Jul 2016 14:20:38 GMT
Keep-Alive:timeout=5, max=100
Server:gunicorn/19.6.0
Transfer-Encoding:chunked
Vary:Accept,Accept-Language,Cookie
X-Frame-Options:SAMEORIGIN

Request Headers:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Access-Control-Request-Headers:accept, content-type, x-csrftoken
Access-Control-Request-Method:POST
Connection:keep-alive
Host:aaa.com
Origin:http://aaa.com
Referer:http://aaa.com/
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36

经过一周的尝试来解决这个问题后,我意识到服务器希望Vary:Cookie在预先发出的请求上是不可能的,因为跨域预先飞行请求不能在其标题中包含cookie。

我开始找到解决此问题的方法,并发现: https://code.djangoproject.com/ticket/13217

“启用django.middleware.locale.LocaleMiddleware会导致django为每个响应添加'Vary:Cookie'标头。” 因此,localMiddleware甚至在飞行前OPTIONS响应中添加标题Vary:Cookie

有许多建议使用djang-cors-header来解决其中的一些问题。但是使用这个包函数等于我在服务器端的设置。

我还找到了漂亮的包:django-dont-vary-on如果安装可以设置装饰器来关闭Vary:cookie,但在我的情况下我需要关闭Vary:cookie仅在OPTIONS响应中。

我对django有点新鲜,实际上甚至无法想象在这种情况下该怎么做。我的每一步都像在矿场上散步一样。 有没有解决方案或其他替代方案?

1 个答案:

答案 0 :(得分:1)

您必须将客户端CORS列入白名单以访问服务器。

如果他们是跨域请求,如果您使用GET,HEAD或POST以外的方法,请求将变为预检。

  

此外,如果使用POST发送带有Content-Type其他的请求数据   比application / x-www-form-urlencoded,multipart / form-data或   text / plain,它变为预检。

它允许处理或拒绝跨域客户端请求的服务器(默认)。

因此,如果您有权访问服务器端应用程序,则可以执行以下操作来获取响应。

在服务器端

在服务器端安装django-cors-headers,并在客户端域或IP上列出白名单(它也是特定于端口的)

pip install django-cors-headers

在settings.py中,将其添加到INSTALLED_APPS

INSTALLED_APPS = (
...
    'corsheaders',
...
)

在MIDDLEWARE_CLASSES中添加corsheaders.middleware.CorsMiddleware

MIDDLEWARE_CLASSES = (
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    '**corsheaders.middleware.CorsMiddleware**',
    'django.middleware.common.CommonMiddleware',
....
)

并定义CORS白名单

CORS_ORIGIN_WHITELIST = (
    'aaa.com',
)

现在,当您在CORS白名单中添加了客户端时,您现在可以成功地发出ajax请求。