什么是 CORS
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器:让运行在一个 origin (domain) 上的Web 应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
比如,站点 http://domain-a.com 的某 HTML 页面通过 的 src 请求 http://domain-b.com/image.jpg。网络上的许多页面都会加载来自不同域的 CSS 样式表,图像和脚本等资源。
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。浏览器一旦发现请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
两种请求
浏览器将 CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:
- HEAD
- GET
- POST
(2)HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。浏览器对这两种请求的处理,是不一样的。
非简单请求
“预检”请求(preflight)
本次项目在前端发送的 HTTP 请求 header 中加入了 x-csrftoken 字段,所以属于非简单请求。
对于非简单请求,浏览器会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。如下所示的请求头部:
预检请求的回应
服务器收到”预检”请求以后,检查了Origin
、Access-Control-Request-Method
和Access-Control-Request-Headers
字段以后,确认允许跨源请求,就可以做出回应。
如果浏览器否定了”预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest
对象的onerror
回调函数捕获。
浏览器的正常请求和回应
一旦服务器通过了”预检”请求,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样,会有一个Origin
头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin
头信息字段。
使用 django-cors-headers 实现 Django 中的 CORS
具体效果就是在 server 返回的 header 中每次加入一个Access-Control-Allow-Origin
和 Access-Control-Allow-Credentials
头信息字段,使得 client 可以发送跨源请求并在 header 中加入 cookie,从而使得 server 可以维护与登录用户之间的 session,从而获得当前用户的 profile 等信息。
1. 使用 pip 安装
pip install django-cors-headers
2. 添加到 setting 的 app 中
INSTALLED_APPS = (
...
'corsheaders',
...
)
3. 添加中间件
MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',# 注意顺序
...
]
4. setting 下面添加下面的配置
# 增加跨域忽略
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000',
'http://localhost:8000',
'http://localhost:8080',
)
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
)