jsonp是一个经典的跨域解决方案,虽然现在使用的很少,但是这种经典的解决方案还是应该了解下,最近在看github中开源的jsonp库,跟着源码加上查阅资料了解了一下jsonp前后端主要的工作,借此来分享一下,有不对的地方大家可以留言指出。
前端需要传递的内容
-
访问的服务器方法名
-
返回json前端调用方法
服务器需要完成的内容
按照前端给的回调函数名包裹成字符串返回
解析github的jsonp项目
传递参数
使用这个库需要传递三个参数
- url
访问的服务器函数
-
opt
1. name:本地接受服务器返回json的函数名称的
2. param、preffix 服务器解析请求并返回json的函数名称与接受服务器返回json的函数名称前缀
3. timeout 等待服务器返回结果的最长时间
-
fn
你希望执行的回调函数
分析jsonp库代码
发起jsonp请求
var target = document.getElementsByTagName('script')[0] || document.head;
script = document.createElement('script');
script.src = url;
target.parentNode.insertBefore(script, target);
代码很简单就是在本地创建script然后发起url请求
处理等待最大时间方法
if (timeout) {
timer = setTimeout(function(){
cleanup();
if (fn) fn(new Error('Timeout'));
}, timeout);
}
jsonp库在发起请求前首先执行这部分代码,当在给定的时间内这个定时器没有清楚就会执行清理函数,这里这里值得注意的是,如果有回调函数也会给回调函数抛一个错误。
清理函数
写通用工具方法,要记得写清理方法处理不再使用的元素,避免浪费资源
function cleanup(){
if (script.parentNode) script.parentNode.removeChild(script);
window[id] = noop; // 将处理服务器返回数据函数赋值为空函数
if (timer) clearTimeout(timer);
}
-
首先清理了发起jsonp请求的script标签
-
接着清理监听等待函数返回最大时间的定时器
-
并将本地监听函数设置为空函数。
监听服务器返回
window[id] = function(data){
cleanup(); // 不要忘记清理
if (fn) fn(null, data);
};
在window对象上监听远端返回,这个id就是前边设置的参数组装而成的,这里要注意一下这里不能完了执行清理函数,以防资源浪费
服务器处理部分
const pathName = url.parse(req.url).pathname; // 获取访问服务器的函数名称
const queryData = qs.parse(req.url.split('?')[1]); // 获取请求参数部分
if (pathName === '/jsonp' && queryData['callback']) {
res.writeHead(200, {
'Content-Type': 'application/json;charset=utf-8' // 返回类型为json
});
var data = {
name: 'zhouyijun'
}
res.end(queryData.callback + `(${JSON.stringify(data)})`) // 返回值,要记得将json对象转换为字符串
}
这里代码比较简单就是通过url解析参数,分发给对应的处理函数,并且取出终端回调函数名称使用字符串拼接成结果返回给终端。
网友评论