跨域 ajax 选项错误 403 (Django)
Posted
技术标签:
【中文标题】跨域 ajax 选项错误 403 (Django)【英文标题】:Cross Domain ajax OPTIONS error 403 (Django) 【发布时间】:2016-11-06 08:10:42 【问题描述】:我正在使用 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 on pre-flighted request 这是不可能的,因为跨域 pre-flight 请求的标头中不能包含 cookie。
我开始为这个问题寻找一些解决方案,并发现: https://code.djangoproject.com/ticket/13217
“启用 django.middleware.locale.LocaleMiddleware 会导致 django 在每个响应中添加一个 'Vary: Cookie' 标头。” 所以 localMiddleware 甚至在飞行前的 OPTIONS 响应中添加了 header Vary: Cookie
有很多建议可以使用djang-cors-header
来解决其中的一些问题。但是使用这个包功能等于我在服务器端的设置。
我还发现了漂亮的包:django-dont-vary-on
,如果安装它可以设置装饰器关闭 Vary:cookie,但在我的情况下,我只需要在 OPTIONS 响应中关闭 Vary:cookie。
我对 django 有点陌生,实际上甚至无法想象在这种情况下该怎么做。我的每一步都像走在雷区。 有什么解决方案或替代方案吗?
【问题讨论】:
【参考方案1】:您必须将您的客户端列入 CORS 白名单才能访问服务器。
如果它们是跨域请求,如果您使用 GET、HEAD 或 POST 以外的方法,则请求将被预检。
另外,如果 POST 用于发送 Content-Type other 的请求数据 比 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 请求。
【讨论】:
感谢您的回复!一旦我获得对服务器端的访问权限,我就会尝试您的解决方案 我很高兴它有帮助 :-)以上是关于跨域 ajax 选项错误 403 (Django)的主要内容,如果未能解决你的问题,请参考以下文章
Django 1.9 AJAX 表单 CSRF 令牌 403 错误 - “未设置 CSRF cookie”
Django 中间件使用 ajax 使用 HTTPS POST 引发 403 错误