一、原理
jsonp
的核心原理是利用script
标签没有同源限制的方式,可以发送跨域的get
请求(只能发送get
请求)。script
标签中的src
属性将请求参数和当前请求的回调函数名拼接在链接上。最终由服务端接收到请求之后拼接成前端可执行的字符串的形式返回。这个结果字符串最终会在前端的script标签中解析并执行。
利用<script>
标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的JSON
数据。JSONP
请求一定需要对方的服务器做支持才可以。
JSONP
和AJAX
对比:JSONP
和AJAX
相同,都是客户端向服务端发送请求,从服务端获取数据的方式。但AJAX
属于同源策略,JSONP
属于非同源策略(跨域请求)。JSONP
优缺点:JSONP
优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅仅支持get
方法具有局限性,不安全,可能会遭受XSS
攻击。
二、实现
1.正常实现
- 将
jsonp
回调函数的名称callbackName
拼接到src
上 - 构建一个
script
标签,设置它的src
属性 - 在全局设置一个
callbackName
回调函数,等待script
标签请求结束,并调用
/**
* jsonp获取请求数据
* @param {object}options
*/
function jsonp(options) {
// console.log(options);
// 1. 产生不同的函数名(函数名随机)
let callBackName = 'itLike' + Math.random().toString().substr(2)+Math.random().toString().substr(2);
// console.log(callBackName);
// 2. 产生一个全局函数
window[callBackName] = function (params) {
// console.log(params);
// console.log(options.success);
if(params !== null){
options.success(params);
}else{
options.failure(params);
}
// 2.1 删除当前脚本标签
scriptE.remove();
// 2.2 将创建的全局函数设为null
window[callBackName] = null;
};
// 3. 取出url地址
let jsonpUrl;
if(options.data !== undefined){
jsonpUrl = options.url + '?' + options.data + '&callBack=' + callBackName;
}else {
jsonpUrl = options.url + '?callBack=' + callBackName;
}
// console.log(jsonpUrl);
// 4. 创建script标签
let scriptE = document.createElement('script');
scriptE.src = jsonpUrl;
document.body.appendChild(scriptE);
}
服务端(express)
router.get('/api/v1', function(req, res, next) {
res.json({
'name': '前端收割机',
'address': '广东',
'intro': '前端技术交流公众号'
});
});
调用jsonp
btn.addEventListener('click', ()=>{
jsonp({
url: 'http://localhost:3000/api/v1',
data: 'name=前端收割机&age=20',
success: function (data) {
console.log(data);
},
failure:function(data){
console.log(数据请求失败);
}
});
});
2.利用promise封装
- 声明一个回调函数,其函数名(如
show
)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data
) - 创建一个
<script src=>
标签 ,把那个跨域的API
数据接口地址,赋值给script
的src
, 还要在这个地址中向服务器传递该函数名(可以通过问号传参?callback=show
)。 - 服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是
show
,它准备好的数据是show('前端收割机')
。 - 最后服务器把准备的数据通过
HTTP
协议返回给客户端,客户端再调用执行之前声明的回调函数(show
),对返回的数据进行操作。
/**
* jsonp获取请求数据
* @param {string}url
* @param {object}params
* @param {function}callback
*/
function jsonp({
url, params, callback }) {
return new Promise((resolve, reject) => {
let script = document.createElement('script');
params = JSON.parse(JSON.stringify(params));
let arrs = [];
for (let key in params) {
arrs.push(`${
key}=${
params[key]}`);
}
arrs.push(`callback=${
callback}`);
script.src = `${
url}?${
arrs.join('&')}`;
document.body.appendChild(script);
window[callback] = function (data) {
resolve(data);
document.body.removeChild(script);
}
})
}
服务器(express
)
// 后端响应
// 这里用到了 express
var express = require('express');
var router = express.Router();
var app = express();
router.get('/say',function(req,res,next) {
//要响应回去的数据
let data = {
username : 'zs',
password : 123456
}
let {
wd , callback} = req.query;
console.log(wd);
console.log(callback);
// 调用回调函数 , 并响应
res.end(`${
callback}(${
JSON.stringify(data)})`);
})
app.use(router);
app.listen(3000);
调用jsonp
// 前端调用
btn.addEventListener('click', ()=>{
jsonp({
url: 'http://localhost:3000/say',
params: {
wd: '前端收割机'
},
callback: 'show'
}).then(data => {
console.log(data)
});
});
三、总结
基本原理:利用 script
标签的 src
没有跨域限制来完成实现。
优缺点:只能 GET
;兼容性好。
简单实现:通过 url, params, callback
来定义 JSONP()
方法的参数。
参考连接:https://juejin.cn/post/6844904094973296654#heading-5
转载:https://blog.csdn.net/imagine_tion/article/details/115475157
查看评论