什么是跨域
跨域(跨源)是指浏览器从一个源的网页去请求另一个源,源指的是域名、端口、协议
以下都属于跨域问题:
域名:
主域名不同: http://www.baidu.com/index.html –> http://www.sina.com/test.js
子域名不同: http://www.666.baidu.com/index.html –> http://www.555.baidu.com/test.js
域名和域名ip: http://www.baidu.com/index.html –> http://180.149.132.47/test.js
端口:
http://www.baidu.com:8080/index.html –> http://www.baidu.com:8081/test.js
协议:
http://www.baidu.com:8080/index.html –> https://www.baidu.com:8080/test.js
为什么要考虑跨域问题
因为Ajax不能跨域, 一旦客户端和服务端的不在一台服务器, 则需要考虑跨域访问的问题
同源策略
同源策略是浏览器的一项最为基本同时也是必须遵守的安全策略
同源策略的存在,限制了“源”自A的脚本只能操作“同源”页面的DOM,“跨源”操作来源于B的页面将会被拒绝
所谓的“同源”,必须要求相应的URI的域名、端口、协议均是相同的
使用Ajax发送请求的方式
现有如下的视图函数:
# views.py
def index(request):
return render(request,'index.html')
def get_data(request):
return JsonResponse({'name':'慕容雪痕'})
现在分别使用JavaScript和jQuery去获取数据
JavaScript
// index.html
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','http://127.0.0.1:8000/getdata',true)
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200){
console.log(xhr.responseText)
}
}
</script>
$.ajax
// index.html
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script>
$.ajax({
type: 'GET',
url: 'http://127.0.0.1:8000/getdata/',
success: function (data) {
console.log(data)
},
error(e) {
console.log(e)
}
})
</script>
$.get
// index.html
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script>
$.get('http://127.0.0.1:8000/getdata/', function (data) {
console.log(data)
})
</script>
$.post
// index.html
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script>
$.ajaxSetup({
data:{csrfmiddlewaretoken:'{{ csrf_token }}'}
})
$.post('http://127.0.0.1:8000/getdata/', function (data) {
console.log(data)
})
</script>
使用上面几种方法会造成跨域问题,当使用http://127.0.0.1:8000/index/访问时,可以正常得到数据,使用http://localhost:8000/index/访问就得不到数据,报如下错误
Access to XMLHttpRequest at 'http://127.0.0.1:8000/getdata' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
解决跨域问题
让服务器支持跨域(推荐)
(1) 安装django-cors-headers
pip install django-cors-headers
(2) 配置settings.py文件
INSTALLED_APPS = [
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
]
# 跨域增加忽略
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
# 跨域允许的请求方式(可选)
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
)
# 跨域允许的头部参数(可选)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
)
(3) 使用ajax请求就可以实现跨域
使用 JSONP
一种非Ajax技术,需要前后端同时支持,只能用于GET请求
浏览器只对XMLHttpRequest请求有同源请求限制,而对script标签src属性、link标签ref属性和img标签src属性没有这种限制,利用这个“漏洞”就可以很好的解决跨域请求。
JSONP就是利用了script标签无同源限制的特点来实现的,当向第三方站点请求时,我们可以将此请求放在script标签的src属性里,这就如同我们请求一个普通的JS脚本,可以自由的向不同的站点请求
// index.html
<script src="http://127.0.0.1:8000/getdata"></script>
访问index.html,结果如下,证明跨域调用成功
[10/Aug/2019 09:56:08] "GET /index/ HTTP/1.1" 200 206
[10/Aug/2019 09:56:08] "GET /getdata/ HTTP/1.1" 200 36
JSONP基本使用如下:
例:index.html代码如下
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script>
$.ajax({
url: 'http://127.0.0.1:8000/getdata/',
dataType: 'JSONP', // 使用JSONP
jsonp: 'callback', // 传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback: 'fn', // 自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
// 相当于在url中添加参数callback=fn
})
function fn(data) {
console.log('--fn--:',data)
// --fn--: {name: "慕容雪痕"}
}
例:views.py代码如下
def get_data(request):
callback = request.GET.get('callback')
print(callback) # fn
data = {"name":"慕容雪痕"}
return HttpResponse('%s(%s)'%(callback,data))
例:在百度搜索框中输入qixijie,在输入框下方会有许多提示词汇(参数wd=qixijie)
// index.html
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script>
url = 'https://www.baidu.com/sugrec?pre=1&p=3&ie=utf-8&json=1&prod=pc&from=pc_web&sugsid=1437,21118,29523,29521,29098,29568,28832,29221&wd=qixijie&req=2&bs=%E4%B8%83%E5%A4%95%E8%8A%82&pbs=%E4%B8%83%E5%A4%95%E8%8A%82&csor=7&pwd=qixiji&cb=jQuery1102040275346927984423_1565401956369&_=1565401956483'
$.ajax({
url: url,
dataType: 'JSONP',
jsonp: 'cb',
jsonpCallback: 'fn',
})
function fn(data) {
console.log('--fn--:',data)
}
</script>
访问index.html,结果如下: