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,消息已经收到,然后再执行其他逻辑

至此两个网站的通信就结束了,有问题或者有错误可以再评论区提出来,以供大家探讨,谢谢