协议配置平台中用了静态JSONP的方式解决问题;关于协议配置平台,参照这里,第一个就是。
JSONP原理
在页面上动态创建一个 script 标签,src 指向接口地址,将接口返回内容作为一段 js 执行;
接口返回内容格式为:callbackName(data),即 回调函数名称(需要传递的数据) 这种形式,其中,回调函数名称是页面调用接口时通过参数传过来的,参数名一般为 callback 或 cb;
页面在动态创建 script 标签之前,按照约定的规则或名称注册全局的回调函数;当接口返回内容时,会作为 js 执行,调用回调函数,将数据传入函数内部;
静态JSONP接口
第一部分中,回调函数名称是由页面决定的,网页传什么名称,服务端就返回什么名称;
如果接口/js文件是一个静态的呢,回调函数名称肯定也只能写死,按照上面的逻辑,如果写死了回调函数名称,整个流程并未受到影响;
为什么用静态文件做接口?
团队内部并没有后端开发,部署一套稳定的线上 JSONP 转换接口成本太高(申请服务器、开发、接入云存储、部署,坑太多);
协议配置平台中,word 可以转为 html,如果将格式化好的 html 包装成 jsonp 格式,做成一个静态的 js 文件,页面就可以通过一个写死的回调函数名称动态获取到 html 的内容了。
这样就可以解决某些场景下的问题:活动页中,活动规则用弹框的形式展现,内容想要动态配置,还不想用iframe;
协议配置平台中,每一个文件上传之后,都会进行重命名,名称是用 UUID 进行替换的 (项目实际用的时候,把中间的连字号去掉了,只保留了32位数字字母;严格说来,还不是标准的UUID)。
维基百科中UUID的定义:
UUID 基本可以认为是唯一的,作为文件名是没有问题的,将此 UUID 稍作修改,也可以作为回调函数名称;这样,文件名和回调函数也能保持统一;
项目中,用了 “cb_uuid” 来作为回调函数名称,JSONP对应的 js 文件名也是同一个 UUID:
调用的相关代码
如果引用了 jquery 或 zepto,直接配置回调函数名就可以调用了:
var url = '//a.com/protocols/jsonp/69d9d29d6b7b536833edceadee954d82.js';
$.ajax({
url: url,
dataType: "jsonp",
jsonpCallback: "cb_69d9d29d6b7b536833edceadee954d82",
success: function (result) {
console.log(result);
},
error: function () {
}
});
或者用原生 js 封装一下:
;(function () {
window.loadRuleCont = function (opts) {
opts = opts || {};
opts.timeout = opts.timeout || 5000;
var jsonpUrl = opts.url;
var success = opts.success;
var error = opts.error;
var timer = null;
var data = opts.data;
var noArgsUrl = jsonpUrl.split("?")[0];
var name = noArgsUrl.replace(/[\s\S]+jsonp\/([\s\S]+)\.js/gmi, "$1"); // /jsonp/21ac67e6e4ceaf1d073d6688f435abbd.js
var cbName = "cb_" + name;
var head = document.getElementsByTagName("head")[0];
window[cbName] = function (result) {
success && success(result);
window[cbName] = null;
clearTimeout(timer);
};
var script = document.createElement("script");
script.src = jsonpUrl;
head.appendChild(script);
timer = setTimeout(function () {
window[cbName] = null;
head.removeChild(script);
error && error("");
}, opts.timeout);
}
})();
调用上面封装的方法:
var url = '//a.com/protocols/jsonp/69d9d29d6b7b536833edceadee954d82.js';
window.loadRuleCont({
url: url, // jsonp地址,从协议列表后的jsonp按钮获得
timeout: 2000, // 超时时间
success: function (html) {
console.log(html)
},
error: function () {
}
});