0%

JSONP原理

jsonp本质上是利用<script>不受同源策略限制的特性,创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。

案例

views.py

1
2
def abc(request):
return HttpResponse("rion")

js

1
2
3
4
5
6
7
$.ajax({
url: "http://127.0.0.1:8002/abc/",
type: "get",
success:function (res) {
console.log(res);
}
})

打开页面后

因为同源策略限制跨域发送ajax请求。

细心点的同学应该会发现我们的views.py其实已经接收到了请求并返回了响应,是浏览器对非同源请求返回的结果做了拦截。

我们使用cdn方式引用的jQuery文件也是跨域的,它就可以使用。

同样是从其他的站点拿东西,script标签就可以。那我们能不能利用这一点搞点事情呢?

修改html文件

1
2
3
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script src="http://127.0.0.1:8002/abc/"></script>

我们刷新一下页面

看来后端返回的响应已经被拿到了,只不过把rion当成了一个变量来使用,但是该页面上却没有定义一个名为rion的变量。所以出错了。

定义一个rion变量

1
2
3
4
5
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var rion = 100;
</script>
<script src="http://127.0.0.1:8002/abc/"></script>

这次就不会报错了。

那可不可以定义一个函数呢?

1
2
3
4
5
6
7
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
function rion() {
console.log("选我不后悔!");
}
</script>
<script src="http://127.0.0.1:8002/abc/"></script>

同时把返回的响应也改一下:

1
2
def abc(request):
return HttpResponse("rion()")

我返回的 rion(),页面上拿到这个响应之后直接执行了rion函数!

那函数中可不可以传递参数呢?

1
2
3
4
5
6
7
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
function rion(res) {
console.log(res);
}
</script>
<script src="http://127.0.0.1:8002/abc/"></script>
1
2
3
def abc(request):
res = {"code": 0, "data": ["SNIS-561", "SNIS-517", "SNIS-539"]}
return HttpResponse("rion({})".format(json.dumps(res)))

我们通过script标签的跨域特性来绕过同源策略拿到想要的数据了!!!

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。

但是我们更多时候是希望通过事件触发数据的获取,而不是像上面一样页面一刷新就执行了,这样很不灵活。

其实这很好解决,我们可以通过javascript动态的创建script标签来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
function rion(res) {
console.log(res);
}
function addScriptTag(src){
var scriptEle = document.createElement("script");
$(scriptEle).attr("src", src);
$("body").append(scriptEle);
$(scriptEle).remove();
}
$("# b1").click(function () {
addScriptTag("http://127.0.0.1:8002/abc/")
})
</script>

这样当我们点击b1按钮的时候,会在页面上插入一个script标签,然后从后端获取数据。

为了实现更加灵活的调用,我们可以把客户端定义的回调函数的函数名传给服务端,服务端则会返回以该回调函数名,将获取的json数据传入这个函数完成回调。

参考 & 引用

https://www.cnblogs.com/rain-chenwei/p/9520240.html