一般情况下我们的请求只能给自己的网站发送请求,如果给别的网站发送请求时,浏览器会进行同源限制,跨域请求就是我们的网站如果要获取其他网站的数据的话,可以通过一下方式实现
例如:要获得以下数据
def get_data(request):
return HttpResponse('数据')
使用代码完成跨域请求
request发送请求的时候跨域无限制
def test1(request):
response = requests.get('http://127.0.0.1:8000/get_data/')
return render(request, 'test1.html', {'response': response})
在前端显示
{{ response.text }}
jsonp实现跨域请求
别人数据
def get_data(request):
func_name = request.GET.get('callback')
return HttpResponse('%s("数据")' % func_name)
使用jsonp实现跨域请求
<script>
function func(arg){
console.log(arg)
}
$.ajax({
url: "http://127.0.0.1:8000/get_data/",
type: 'GET',
dataType: 'JSONP',
jsonp: 'callback',
jsonpCallback: 'list'
});
</script>
注意:
首先,要让别人对数据进行处理
其次,为了让获得的数据易读,需要将数据进行list
其原理是使用带有src的标签不会收到同源限制,而且要求自己定义一个数据,使用标签引入,而且要求别人也要在数据外面包一层数据,如下
自己获得
<script>
function func(arg) {
console.log(arg);
}
</script>
<script src="http://127.0.0.1:8000/get_data/?callback=func"></script>
我们也可以手动创建标签
<script>
function func(arg) {
alert(arg);
document.head.removeChild(tag);
}
function jsonp(url){
tag = document.createElement('script');
tag.src = url;
document.head.appendChild(tag);
}
jsonp('http://127.0.0.1:8000/get_data/?callback=func')
</script>
应用场景:
调用者需要和数据提供者协商,首先需要数据提供者提供一个API,然后互相商讨使用哪一种方式提取数据,如果使用jsonp格式提取数据的话需要数据提供者对数据进行一定的处理(获得callback,然后使用callback包裹你的数据),如果不想让数据提供者麻烦的话,就只能用自带的request模块来实现
core方法
首先要明白,jsonp进行跨域请求的方法是绕过同源策略,使用带有src的标签进行请求
其次,浏览器为什么会进行同源策略,其实在请求可以顺利的到达对方的URL,也同样能取到数据,但是在返回的时候少了Access-Control-Allow-Origin 响应头,因此,我们的做法就是将头加进去
别人数据
def get_data(request):
response = HttpResponse('数据')
response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8899' # 如果为*的话对所有请求有效
return response
这样让别人的数据进行处理之后我们自己就按照一般情况请求就可以了
$.ajax({
url: 'http://127.0.0.1:8000/get_data/',
type: 'GET',
success: function (data) {
console.log(data);
}
})
如果我们给别人提供数据的话,如果允许所有的人都可以请求的话,使用中间件比较好
注意:
我门正规的请求称为简单请求,但是,有时候发请求的时候会发送复杂请求,请求方式改变或者请求头的改变可以变为复杂请求,
如果发送的是复杂请求的话,首先会发送一个option,然后发送数据,复杂请求接受到的request.method是option
因此数据提供者应该在接受请求的时候进行一个判断,如果request.method的话,将请求方式和请求头进行修改,然后再发送数据
由于复杂请求发送两次,严重影响效率,因此我们应该尽量避免发送复杂请求
兼容复杂请求代码如下
def get_data(request):
if request.method == "OPTIONS":
# 预检
response = HttpResponse()
response['Access-Control-Allow-Origin'] = "*"
# response['Access-Control-Allow-Methods'] = "PUT"
response['Access-Control-Allow-Headers'] = "xxx" # 注意在前端也是要一样的
return response
elif request.method == "GET":
response = HttpResponse("机密数据")
response['Access-Control-Allow-Origin'] = "*"
return response
跨站获取相应头
默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要再服务器端设置Access-Control-Expose-Headers。
跨站传cookie
在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。
如果想要发送:
- 浏览器端:XMLHttpRequest的withCredentials为true
- 服务器端:Access-Control-Allow-Credentials为true
- 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符