Niffler

X2.16.16340232-在 Django 中实现 HTTP CORS

Posted By 16340232

什么是 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-urlencodedmultipart/form-datatext/plain

凡是不同时满足上面两个条件,就属于非简单请求。浏览器对这两种请求的处理,是不一样的。


非简单请求

“预检”请求(preflight)

本次项目在前端发送的 HTTP 请求 header 中加入了 x-csrftoken 字段,所以属于非简单请求。

对于非简单请求,浏览器会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。如下所示的请求头部:

prefligt


预检请求的回应

服务器收到”预检”请求以后,检查了OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

response

如果浏览器否定了”预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。


浏览器的正常请求和回应

一旦服务器通过了”预检”请求,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

request


使用 django-cors-headers 实现 Django 中的 CORS

具体效果就是在 server 返回的 header 中每次加入一个Access-Control-Allow-OriginAccess-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',
)