-
跨域
跨域指的就是“跨域资源共享(Cross-Origin Resource Sharing, CORS)”,是一个“W3C标准”,当一个资源从与该资源本身所在的服务器的不同域或者不同端口请求一个资源时,就会发起一个跨域HTTP请求。
即浏览器对于javascript的同源策略的限制,例如a.cn下面的js不能调用b.cn中的js,对象或数据(因为a.cn和b.cn是不同域),所以跨域就出现了. -
同源
请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同.
协议相同:比如http://
域名相同:比如“www.example.com”
端口相同:比如同为8000(默认端口80可以省略)
同时满足满足以上三个条件的才可以被称为同源。
同源的目的是为了保证用户信息的安全,防止恶意网站窃取数据。
- 回归Django的跨域的解决方案一共需要以下五步
-
1.pip 安装:
在所使用的虚拟环境中安装:
pip install django-cors-headers
-
2.将其注册到Django 项目setting的INSTALLED_APPS中:
INSTALLED_APPS = (
…,
‘corsheaders’,
…
) -
3.添加中间件类来监听响应
‘CorsMiddleware’ 为了方便可以放在最外层,推荐尽可能放置在生成响应的任何中间件之前,如Django ‘CommonMiddleware’ ,如果不是,则会跨域失败
MIDDLEWARE = [
…,
’ corsheaders.middleware.CorsMiddleware’,
’ django.middleware.common.CommonMiddleware’,
] -
4.需要在Django中使用的配置
CORS_ORIGIN_WHITELIST
允许白名单,允许执行跨站请求的主机列表(疑问添加’null’,待解决),默认是:[ ]
如:
-
CORS_ORIGIN_WHITELIST = (
'12.0.0.1:8000',
'google.com',
'localhost:8000',
)
CORS_ALLOW_CREDENTIALS
跨域请求时是否允许携带Cookie,默认是False
其中这几点也可以通过设置 CORS_ALLOW_CREDENTIALS = True
来实现,CORS_ORIGIN_ALLOW_ALL如果是True,将不再使用白名单,并允许所有主机执行跨站点请求,默认是False
- 5.需要在Django中使用的配置
# 这是实现最简单的能够解决CORS问题的方式(在settings.py中同时设置CORS_ORIGIN_ALLOW_ALL = True)
from django.utils.deprecation import MiddlewareMixin
class MiddleTest(MiddlewareMixin):
def process_response(self,request,response):
response['Access-Control-Allow-Origin'] = '*'
return response
同时设置项目的settings.py如下即可(其中METHODS和HEADERS方法非必须
,可以根据自己需求设置)
或者可以根据自己的需求进行一些扩展
class CORSMiddleware(MiddlewareMixin):
def process_response(self,request,response):
# 添加响应头
# 允许你的域名来获取我的数据
response['Access-Control-Allow-Origin'] = "*"
# 允许你携带Content-Type请求头
# response['Access-Control-Allow-Headers'] = "Content-Type"
# 允许你发送DELETE,PUT
# response['Access-Control-Allow-Methods'] = "DELETE,PUT"
return response
实现以上配置功能即可进行跨域
django还有一些其他的配置扩展(可以根据需求进行添加)
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- CORS_ORIGIN_REGEX_WHITELIST
当你有大量子域名需要添加到白名单的时候,‘CORS_ORIGIN_WHITELIST’ 就不太适用了,可以通过此设置将对HTTP请求进行正则匹配,匹配成功则允许跨域,否则不允许,默认是[ ]
如:
CORS_ORIGIN_REGEX_WHITELIST = (
r’^(https??/)?(\w+.)?google.comKaTeX parse error: Expected 'EOF', got '\w' at position 20: …'^(https?://)?(\̲w̲+\.)?baidu\.com’,
) - CORS_URLS_REGEX
一个正则表达式,限制所有进行CORS 的URL,默认是 r’^.’ 即匹配所有URL,当您只需要一部分请求CORS时,很有用,例如API /api/:
CORS_URLS_REGEX = r"^/api/.$" - CORS_ALLOW_METHODS
允许跨域的请求方式,一般使用默认,如下:
CORS_ALLOW_METHODS = (
‘DELETE’,
‘GET’,
‘OPTIONS’,
‘PATCH’,
‘POST’,
‘PUT’,
)
扩展添加额外的请求方式时可以导入默认值,如:
from corsheaders.defaults import default_methods
CORS_ALLOW_METHODS = default_methods + (
‘POKE’ # 自定义请求方式
)
CORS_ALLOW_HEADERS
允许跨域的请求头,一般使用默认值,如:
CORS_ALLOW_HEADERS = (
‘accept’,
‘accept-encoding’,
‘authorization’,
‘content-type’,
‘dnt’,
‘origin’,
‘user-agent’,
‘x-csrftoken’,
‘x-requested-with’,
)
同上一样,可以导入默认值,来实现自定义请求头的扩展
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = default_headers + (
‘my-custom-header’,
) - CORS_EXPOSE_HEADERS
向浏览器公开的HTTP请求头列表,默认是 [ ]
CORS_MODEL
几乎用不到,留坑,以后扩展。默认为None
CORS_PREFLIGHT_MAX_AGE
浏览器或者客户端可以缓存预检响应的秒数,如果是0或者任何假值,则再次发送请求时,还需要进行预检,默认是86400(一天)
扩展:预检是发送“非简单请求”时,发送真正请求前的额外请求
简单请求与非简单请求
-
同时满足以下两大条件,就属于简单请求,否则就是复杂请求
一、请求方式
1.HEAD
2.GET
3.POST
二、请求头信息
1.Accept
2.Accept-Language
3.Content-Language
4.Last-Event-ID
5.Content-Type 只限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain -
针对简单请求和复杂请求,浏览器的处理方式
-
简单请求
浏览器直接发出CORS 请求 ,具体来说就是在请求头信息中添加一个"Origin"的字段
Origin字段的作用,就是说明本次请求来自哪个源(协议+域名+端口),服务器根据这个值,决定是否同意这次请求-
如果Origin指定的源不在许可范围内,服务器会返回一个头信息里面不包含“Access-Control-Allow-Origin”字段的正常响应,浏览器发现没有该字段后,就会抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,因为这种HTTP回应的状态码可能是200,所以无法通过状态码识别或进行条件判断。
-
如果Origin指定的源在许可范围内,服务器的返回的响应里面,会多出四个头信息字段,其中三个字段与CORS请求相关,且都是以“Access-Control-” 开头
Access-Control-Allow-Origin
该字段是必须的,它的值要么是请求时Origin字段的值,要么时一个“*”,表示接收任意域名的请求
Access-Control-Allow-Credentials
该字段可选,值是一个布尔值,表示是否允许发送Cookie,默认为False
如果需要将Cookie 包含在请求头中,一起发给服务器,则必须将此字段设为True
Access-Control-Expose-Headers
该字段可选,CORS请求时,XMLHttpRequest 对象的getResponseHeader()方法只能拿到6个基本字段“Cache-Control(缓存控制)”,“Content-Language(指明报文体使用的语言,譬如:ch,fr,en,ja等等)”,“Content-Type(指定报文体的类型,比如text/xml,image/jpeg等等,同时可以通过charset来指定内容所使用的字符集)”,“Expires(用来控制缓存的失效期,如果Cache-Control设置“max-age”或"s-max-age",则会忽略该字段)”,“Last-Modified(请求成功后用来标记此文件在服务器端最后被修改的时间,如果第二次进行请求发现服务器资源没有发生变化,此字段值不变,则自动重定向并返回304(Not Changed)的状态码)”,“Pragma(HTTP/1.0时功能比较弱的缓存机制,HTTP/1.0存在该字段时会忽略“Expires”和“Cache-control”字段)”,如果希望该方法能拿到其他字段,就必须要在‘Access-Control-Expose-Headers’中指定
2 非简单请求
对服务器有特殊要求的请求,常见的如请求方式时“PUT”或"DELETE",或者请求头Content-Type字段的类型是application/json时
非简单请求的CORS请求,会在正式通信前,增加一次HTTP查询请求,称为“预检(preflight)”请求
预检其实就是做检查,检查如果通过则允许传输数据,检查不通过则不能发送真正要发送的消息
预检的请求方式:OPTIONS, 表示这个请求时用来询问的
预检的请求头信息的关键字段
Origin
表示请求来自哪个源
Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些请求方式,会在“CORS_ALLOW_METHODS”中查找,存在则通过,不存在则不允许跨域,或在“CORS_ALLOW_METHODS”中添加该请求方式
Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,会在“CORS_ALLOW_HEADERS”中查找,存在则通过,不存在则不允许跨域,或在“CORS_ALLOW_HEADERS中”添加该头信息 -
-
另外一种跨域的解决方案
JSONP
只能发送GET请求,主要修改在前段部分,后端需要做约束修改,发jsonp请求。优势在于支持老式浏览器,以及向不支持CORS的网站请求数据。
如果想查看更详细的参考可以看这位大佬的github,非常全面:
https://github.com/ottoyiu/django-cors-headers/