Django的跨域请求--JSONP的本质
通常我们在写web端的代码,可以通过url获得想对应的响应数据如:
1.urls.py
urlpatterns = [
url(r'^get_data/', views.data),
]
2.views.py
def data(request):
return HttpResponse("机密数据")
而对于这个“机密数据”我们可以通过url直接可以获取如下
也可以通过其他的终端获取如下
那么现在有一个问题如果有个第三方的web端通过它的页面想让这段机密数据在自己的web页面上进行显示时如何实现:
第一步:
新创建一个Django的web服务:
1、urls.py
2.views.py
def index(request):
return render(request,"index.html")
3.html
4.启动web(因为同时启动两个Django需将对应的端口修改)
现在一个web(机密数据),一个web(维基解密),现在的需求就是维基解密想将机密数据在其index的页面进行显示,这个如何完成???
这个方法有很多种:
方法1:通过后端请求:
-
views.py
def index(request): response = requests.get('http://127.0.0.1:8000/get_data/').text return render(request,"index.html",{'response':response})
-
index.html
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="{% static 'jquery-3.2.1.js'%}"></script> </head> <body> <h1>维基解密</h1> <b>{{ response }}</b> </body> </html>
渲染效果
该方法通过后台相当于发送了两次get请求才将数据取到
方法2:前端Ajax获取
-
index.html
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="{% static 'jquery-3.2.1.js' %}"></script> </head> <body> <h1>维基解密</h1> <b>{{ response }}</b> <script> $.ajax({ url:'http://127.0.0.1:8000/get_data/', type:'GET', success:function(arg){ alert(arg) } }) </script> </body> </html>
但是会遇到下面这个情况使我们无法获取数据:
其实这个是我们的浏览器会拦截:
具体浏览器从什么时候进行拦截的我们可以验证
所以这里可以知道其实机密数据的数据已经发送过来只是被浏览器给拦截,那对于这种情况我们应该如何绕过拦截而获取数据??
如何绕过浏览器的同源策略
一、JSONP方式
从以往的前端HTML我们可以知道,其实在HTML的一些标签中有些标签是不受同源策略的影响如:
-
img标签
-
script 标签
-
iframe标签
所以通过这个点我们可以将代码做修改利用这些标签的属性来绕过浏览器的同源策略:
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
<script src="http://127.0.0.1:8000/get_data/"></script>
</head>
<body>
<h1>维基解密</h1>
</body>
</html>
这里我们利用script的src的属性直接将机密数据的url放置,按理应该是可以将数据给我们返回的:
执行的结果如下:
上面显示数据其实我们已经拿到了,但是没有渲染在页面上,报错提醒是该端值未定义!!
这是因为我们使用的是script标签将我们取到的机密数据只是一个单纯的文本格式,而script是渲染js文档的所有显示显示没有定义的变量:
我们可以进行验证如下:
1.现将机密数据作为一个func的函数参数渲染
2.维基解密的index.html的html
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
<script>
function func(arg){
console.log(arg);
}
</script>
<script src="http://127.0.0.1:8000/get_data/"></script>
</head>
<body>
<h1>维基解密</h1>
<b>{{ response }}</b>
</body>
</html>
这段代码我们先定义了func,再用script引入机密数据
3.结果
这样我们很好的绕开了浏览器的同源策略并取到数据
我们还可以进一步的优化代码
views.py
index.html的html代码
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
</head>
<body>
<h1>维基解密</h1>
<input type="button" onclick="jsonp('http://127.0.0.1:8000/get_data?callback=funcxxx')" value="发送JSONP请求">
<script>
function funcxxx(arg) {
alert(arg);
}
function jsonp(url){
var tag = document.createElement('script');
tag.src = url;
document.head.appendChild(tag);
document.head.removeChild(tag);
}
</script>
</body>
</html>
上述代码就是jsonp的本质执行的过程
而在jQuery中提供了jsonp的方式:
index.html的html代码
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
</head>
<body>
<h1>维基解密</h1>
<input type="button" onclick="jsonp()" value="发送JSONP请求">
<script>
function jsonp(){
$.ajax({
url:"http://127.0.0.1:8000/get_data?callback=funcxxx",
type:'GET',
dataType:'JSONP',
success:function(data){
console.log(data);
}
})
}
</script>
</body>
</html>
而这个的实现原理实质是和之前写的源码一样
结论:
**优点:**1.通过jsonp的传输方式我们可以绕开浏览器同源策略。
2.页面不用刷新而获得数据
缺陷:
1.远程数据的本地需要将数据封装在函数中
2.本地需要定义被封装的函数
3.JSONP只能发送GET请求
下面有个实例:
将JX卫视的节目单取到
index.html的html代码
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="{% static 'jquery-3.2.1.js' %}"></script>
</head>
<body>
<h1>维基解密</h1>
<input type="button" onclick="jsonp()" value="发送JSONP请求">
<script>
function list(arg){
console.log(arg)
}
function jsonp(){
$.ajax({
url:"http://www.jxntv.cn/data/jmd-jxtv2.html",
type:'GET',
dataType:'JSONP',
jsonp:'callback',
jsonpCallback:'list'
})
}
//这里的 jsonp:'callback',jsonpCallback:'list相当于
url:"http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list",
</script>
</body>
</html>
结果如下: