CORS:
概念:因为浏览器都有同源策略,为了解决跨域请求,有两种方式,1.JSONP 通过动态生成script的方式,在通过ajax发起请求并获取相应的数据
2.使用CORS的方式,需要浏览器和服务器同时支持,目前所有的浏览器都支持该功能,整个CORS通讯过程都是浏览器自动完成,不需要用户参与,
浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,因此实现CORS通讯的关键是服务器,只要服务器实现了CORS接口就可以跨域通讯。
两种请求:
1.简单请求:
请求方式:HEAD,GET,POST
HTTP的头信息:
.Accept
.Accept-Language
.Content-Language
.Last-Event-ID
.Content-Type 只限于三种值:application/x-www-form-urlencoded,multipart/form-data,tecx/plain
请求流程:
浏览器发现这次跨源ajax是简单请求,就会自动在头信息上添加一个Origin字段,该字段用来说明本次请求来自哪一个源(协议+域名+端口),
服务器根据这个值,决定是否同意这次请求,如果在许可范围内,服务器的响应,会多出几个头信息字段。
1.Access-Control-Allow-Origin: http://api.bob.com #这个字段必须的,*表示接受任何域名的请求
2.Access-Control-Allow-Credentials: true #可选 表示是否可以发送Cookie
3.Access-Control-Expose-Headers: FooBar #getResponseHeader()方法只能拿到6个基本字段之外的其他字段
4.withCredentials:
如果要把Cookie发送到服务器,一方面需要服务器同意Access-Control-Allow-Credentials: true,
另一方面,开发者必须在Ajax请求中打开withCredentials属性 var xhr = new XMLHttpRequest();xhr.withCredentials = true
如果需要发送cookie,Access-Control-Allow-Origin 不能设置为*
A网站:
<input type="button" value="获取用户数据" onclick="getUsers()">
<script src="jquery-1.12.4.min.js"></script>
<script>
function getUsers() {
$.ajax({
url: 'http://127.0.0.1:8000/users/',
type:'GET',
success:function (ret) {
console.log(ret)
}
})
}
</script>
服务商:
class UsersView(views.APIView):
def get(self,request,*args,**kwargs):
ret = {
'code':1000,
'data':'陈太章'
}
response = JsonResponse(ret)
response['Access-Control-Allow-Origin'] = "*"
return response
2.非简单请求:
请求方式:PUT,DELETE
头信息:Content-Type 字段的类型是application/json
请求流程:
1.在正式通信之前,增加一次HTTP查询请求,先询问服务器,当前网页所在的域名是否在服务器的许可名单中,以及是否可以使用头信息,只有得到许可后
浏览器才会发出正式的XMLHttpRequest请求,预检请求的方法是option,表示这个请求是用来询问的,头信息里面的关键字origin表示来自于哪一个源
还包含其他两个特殊的字段,1.Access-Control-Request-Method列出CORS请求会使用到那些方法,2.Access-Control-Request-Headers 列出额外发送的头信息。
2.服务器收到预检后,检查各个字段确认允许跨源请求,就可以做出回应,如果服务器不同意预检请求,就会返回一个正常的HTTP回应,但是不包含CORS相关的头信息,
浏览器就认定,服务器不同意预检,触发错误。
服务器返回CORS相关的字段:
1.Access-Control-Allow-Methods: GET, POST, PUT #表明服务器支持的所有跨域请求方法
2.Access-Control-Allow-Headers: X-Custom-Header # 表明服务器支持的所有头信息字段
3.Access-Control-Allow-Credentials: true #表明可以携带cookie
4.Access-Control-Max-Age: 1728000 #表明预检的有效时间,在此期间,不用在发送另一次的预检
3.服务器通过预检请求后,在预检的有效区内,每次的CORS请求都走简单请求方式。
def options(self, request, *args, **kwargs):
# self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
# self.set_header('Access-Control-Allow-Headers', "k1,k2")
# self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
# self.set_header('Access-Control-Max-Age', 10)
response = HttpResponse()
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Headers'] = 'h1'
# response['Access-Control-Allow-Methods'] = 'PUT'
return response