django之CORS跨域请求
对于想要利用django框架实现前后端分离,首要的问题是解决跨域请求的问题,什么是跨域请求?简单来说就是当前发起的请求的域与该请求指向的资源所在的域不一致。当协议+域名+端口号均相同,那么就是同一个域.
跨域问题
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:(也就是说如果你的请求方法是什么put、delete等肯定是非简单请求) 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,也就是说,如果你发送的application/json格式的数据,那么肯定是非简单请求,vue的axios默认的请求体信息格式是json的,ajax默认是urlencoded的。
* 简单请求和非简单请求的区别? 简单请求:一次请求 非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。 * 关于“预检” - 请求方式:OPTIONS - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息 - 如何“预检” => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过 Access-Control-Request-Method => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过 Access-Control-Request-Headers
报错信息:
解决方案
1.JSONP,比较原始的方法,本质上是利用html的一些不受同源策略影响的标签,例如:<a>,<img>,<iframe>,<script>等,从而实现跨域请求,但是这种方法只支持GET的请求方式。
2.CORS,Cross-Origin Resource Sharing,是一个新的W3C标准,它新增的一组HTTP首部字段,允许服务端声明哪些源站有权限访问哪些资源,换言之,它允许浏览器向声明了CORS的跨域服务器发出XML HttpRequest请求,从而客服Ajax只能同源使用的限制。在django框架中就是利用CORS来解决跨域请求的问题.
1.安装: 1 pip install django-cors-headers
2.修改django项目中的settings.py
1 INSTALLED_APPS = [ 2 'django.contrib.admin', 3 'django.contrib.auth', 4 'django.contrib.contenttypes', 5 'django.contrib.sessions', 6 'django.contrib.messages', 7 'django.contrib.staticfiles', 8 'corsheaders',#这是我们的主角,放在新建的其他项目之前 9 'app01', 10 ] 11 MIDDLEWARE = [ 12 'django.middleware.security.SecurityMiddleware', 13 'django.contrib.sessions.middleware.SessionMiddleware', 14 'corsheaders.middleware.CorsMiddleware', #注意顺序,必须放在这儿 15 'django.middleware.common.CommonMiddleware', 16 'django.middleware.csrf.CsrfViewMiddleware', 17 'django.contrib.auth.middleware.AuthenticationMiddleware', 18 'django.contrib.messages.middleware.MessageMiddleware', 19 'django.middleware.clickjacking.XFrameOptionsMiddleware', 20 ] 21 22 23 24 CORS_ALLOW_CREDENTIALS = True 25 26 CORS_ORIGIN_ALLOW_ALL = True 27 28 # 允许所有的请求头 29 30 CORS_ALLOW_HEADERS = (' * ')
1 INSTALLED_APPS = [ 2 ... 3 'corsheaders', 4 ... 5 ] 6 7 MIDDLEWARE_CLASSES = ( 8 ... 9 'corsheaders.middleware.CorsMiddleware', 10 'django.middleware.common.CommonMiddleware', # 注意顺序 11 ... 12 ) 13 #跨域增加忽略 14 CORS_ALLOW_CREDENTIALS = True 15 CORS_ORIGIN_ALLOW_ALL = True 16 CORS_ORIGIN_WHITELIST = ( 17 '*' 18 ) 19 20 CORS_ALLOW_METHODS = ( 21 'DELETE', 22 'GET', 23 'OPTIONS', 24 'PATCH', 25 'POST', 26 'PUT', 27 'VIEW', 28 ) 29 30 CORS_ALLOW_HEADERS = ( 31 'XMLHttpRequest', 32 'X_FILENAME', 33 'accept-encoding', 34 'authorization', 35 'content-type', 36 'dnt', 37 'origin', 38 'user-agent', 39 'x-csrftoken', 40 'x-requested-with', 41 'Pragma', 42 )
其他解决方案
1 使用Ajax获取json数据时,存在跨域的限制。不过,在Web页面上调用js的script脚本文件时却不受跨域的影响,JSONP就是利用这个来实现跨域的传输。因此,我们需要将Ajax调用中的dataType从JSON改为JSONP(相应的API也需要支持JSONP)格式。 2 JSONP只能用于GET请求。
1 修改views.py中对应API的实现函数,允许其他域通过Ajax请求数据: 2 def myview(_request): 3 response = HttpResponse(json.dumps({“key”: “value”, “key2”: “value”})) 4 response[“Access-Control-Allow-Origin”] = “*” 5 response[“Access-Control-Allow-Methods”] = “POST, GET, OPTIONS” 6 response[“Access-Control-Max-Age”] = “1000” 7 response[“Access-Control-Allow-Headers”] = “*” 8 return response
3.中间件解决
在app下创建一个文件,在其中写如下代码:
接着在settings.py中注册自定义的中间件: