postMessage,addEventListener, 前端跨域请求之js代码解析
我们今天讲讲postMessage,addEventListener,实现跨域信号发送和监听;废话不多说,直接上代码,有码有真相。
Site A:
function sendTo(token){
if (token) {
var url="https://192.168.0.150:44328/thc/index";
var targetWin='_blank';
var feature="width="+ (screen.availWidth - 10) +",height="+(screen.availHeight - 30)+",scrollbars=1,resizable=1";
var popWinHelp=openWin(url,targetWin,feature);
popWinHelp.focus();
var postData = {
"sign":0,
"token":token
}
this.timeOfmsg = setInterval(() => popWinHelp.postMessage(postData, "*"), 1000);
window.addEventListener("message", receiveMessage, false);
}
}
function receiveMessage(){
alert("Got it");
if (event.data.sign == 1) { //from Site B
if (event.data.msg === 'getMsg' && event.data.sign == 1) {
//alert("post message complate, close the timer.");
clearInterval(this.timeOfmsg);
}
}
}
先看重要的1行代码
this.timeOfmsg = setInterval(() => popWinHelp.postMessage(postData, "*"),
这行代码主要是post一个数据给新open 的window,等待对方接受消息,细心的朋友会注意到,紧接着下一行代码是什么意思,难不成自己发消息,自己来监听?我们接下往下聊,带着疑惑我们直接上接受方的代码,也就是跨域方的前端代码
Site B:
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
if ("https://test.thchf.com.cn" == event.origin && event.data.sign == 0) {
let msg = { "sign": 1, "msg": "getMsg" };
window.opener.postMessage(msg, "*");
var thc_token = event.data.token;
localStorage.setItem("thc_token", thc_token);
jQuery.ajax({
type: "get",
url: "/home/index",
beforeSend: function (xhr) {
xhr.setRequestHeader("auth", thc_token)
},
success: function (result) {
window.location.href = window.location.origin + "/home/index";
}
});
} else {
window.location.href = window.location.origin + "/account/login";
}
}
我们先按照正常流程去看,从Site A post消息在Site B来监听,就是第一行代码
window.addEventListener("message", receiveMessage, false);
然后看上面的接受函数,很容易看出,Site B收到监听数据,执行receiveMessage函数,在函数内容,首先处理的是告诉发送方Site A, Site B已经收到监听数据,也是通过postMessage发送信号。
然后回过头看看我们最开始那个疑惑,是不是理解了。Site A post完消息后,立刻去监听,目的是等待对方发送收到消息的信号,可以执行之后的操作 alert("Got it");这样做的目的是防止发送消息后,还没有等待对方收到消息就执行下面的操作。
细心的朋友还有注意点,Site A和Site B都有监听的代码
addEventListener("message", receiveMessage, false);那一来一回会不会错乱,接受了不该接受的消息。
答案当然是存在的,毕竟addEventListener只是定义一个监听事件,并没有指定只监听谁发来的数据信号。所以我们撸一撸逻辑,
Site A发送 => Site B接受 => Site A => do others
为了避免Site A第一次发送完,Site B还没有接收到信号的问题,我们用了
this.timeOfmsg = setInterval(() => popWinHelp.postMessage(postData, "*"),1000);
间隔1s发送一次消息,直到收到Site B返回的收到消息信号,执行SIte A 的receiveMessage函数,在函数内部停止发送 clearInterval,要强调一下,一定要接受SiteB 发送返回信号判断
if (event.data.sign == 1) { //from Site B
至此Site就完成了整个发送任务。
我们再来说说Site B,当Site A还在间隔1s发送信号的时候,Site B开始准备接受其中的一条,然后判断是否是Site A发送的
if ("https://test.thchf.com.cn" == event.origin && event.data.sign == 0)
如果是Site A发送的,就执行
let msg = { "sign": 1, "msg": "getMsg" };
window.opener.postMessage(msg, "*");
告诉Site A,消息已经收到,然后再执行其他逻辑
至此两个网站的通信就结束了,有问题或者有错误可以再评论区提出来,以供大家探讨,谢谢