一、JSONP是什么
在菜鸟教程中是这样说的,JSONP(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
为什么我们从不同的域(网站)访问数据需要一个特殊的技术( JSONP )呢?这是因为同源策略。
同源策略,它是由 Netscape 提出的一个著名的安全策略,现在所有支持 JavaScript 的浏览器都会使用这个策略,所谓同源是指,域名,协议,端口相同。
二、原理
大家应该知道,<img>
的src(获取图片),<link>
的href(获取css),<script>
的src(获取javascript)这三个标签都不符合同源策略,它们可以跨域获取数据。JSONP就是通过动态创建<script>
标签,指向一个需要访问的地址,利用<script>
的src 不受同源策略约束,提供一个回调函数来接收数据来跨域获取数据的。
三、怎么用
1、跨域获取某文件
添加了一个script标签,标签的src指向了另一个域www.ding.com下的practice.js脚本,在网页中定义接受返回数据的callback函数,在该函数中可以随意定制自己的函数来自动处理返回数据。在practice.js脚本中,用callback函数包裹需要请求的数据。
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + "name:" + data.name);
}
</script>
<script type="text/javascript" src="jquery-1.8.3.min.js">
</script>
<script type="text/javascript" src="http://www.ding.com/practice.js"></script>
</body>
</html>
这里调用了跨域的practice.js脚本,practice.js代码如下:
jsonhandle({
"age" : 15,
"name": "John",
})
上边的代码的执行结果是
2、跨域获取数据
在请求的url加入一个callback回调函数用来返回请求的数据,并在js中写入该函数及需要对数据进行的处理。
<script src="http://localhost:3000/article-list?callback=func"><script>
<script>
function func(res) {
alert(res.message + res.name + "你已经" + res.age + "岁了");
}
</script>
服务端:
router.get('/article-list', (req, res) => {
let data = {
message: 'success!',
name: '小明',
age: 18
}
data = JSON.stringify(data)
res.end('func(' + data + ')');
});
jQuery提供了方便使用JSONP的方式
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript" src="jquery-1.8.3.min.js">
</script>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type : "get",
async: false,
url : "http://www.ding.com/student.php?id=1",
dataType: "jsonp",
jsonp:"callback", //请求php的参数名
jsonpCallback: "jsonhandle",//要执行的回调函数
success : function(data) {
alert("age:" + data.age + "name:" + data.name);
}
});
});
</script>
</body>
</html>
封装成一个函数
function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
let script = document.createElement("script");
// 定义一个全局回调函数,若请求返回,则执行里边内容
window[callback] = function(data) {
resolve(data);
document.body.removeChild(script);
}
let arrs = [];
params = { ...params, callback };
for (let key in params) {
arrs.push(params[key]);
}
script.src = `${url}?${arrs.join("&")}`;
document.body.appendChild(script);
});
}
jsonp({
url: "http://localhost:3000/say",
params: { wd: "Iloveyou" },
callback: "show"
}).then(data => {
console.log(data);
});
四、优缺点
优点:
完美的解决了在测试或者开发中获取不同域下的数据的问题,用户只需传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
缺点:
1. 只支持get请求而不支持post请求
2. 存在安全性问题