HTML5跨文档消息通信之postMessage API的探索案例

前提条件:首先,页面需要部署在web服务器上;其次,两个页面必须来自不同的域。

postMessage API提供了一种交互方式,使得不同源的ifarme可以与其父页面进行通信。这个案例,小部件被包含在一个ifarme中,因此不能直接访问其父窗口。当聊天部件接收到聊天消息时,它可以用postMessage向父页面发送一个消息,以便父页面提醒聊天部件的用户接收到了新消息。同理,父页面也能将用户的状态发送给聊天部件,父页面和部件通过把彼此的源加到可信源的白名单中,就都能收到来自对方的消息。

127.0.0.1文件postMessagePortal.html

<!DOCTYPE html>
<title>门户页面标题</title>
<link rel="stylesheet" href="styles.css">
<script>

var trustedOrigin = "http://www.vserve365.com";
var defaultTitle = "门户页面标题";
var notificationTimer = null;

/**
 * 消息事件是一个拥有data(数据)和origin(源)属性的DOM事件。data属性是发送方传递的时间消息,而origin属性是发送来源。有了origin属性,接收方能轻易地忽略掉来自不可信源的消息:根据可信源的列表能方便地判断来源是否可靠。
 */
function messageHandler(e) {
    if (e.origin == trustedOrigin) {
        notify(e.data);
    } else {
        // 忽视来自其他源的消息
    }
}

/**
 * 添加一个与聊天部件通信的函数。它用postMessage发送一个状态,更新新门户页面中的部件ifarme。对于在线的聊天应用,可以用这种方式来更新用户在线状态(在线、离开等)
 */
function sendString(s) {
    document.getElementById("widget").contentWindow.postMessage(s, trustedOrigin);
}

/**
 * 通知函数
 */
function notify(message) {
    stopBlinking();
    blinkTitle('[新消息提醒]' + message, defaultTitle);//闪烁标题信息
}

/**
 * 停止闪烁标题函数
 */
function stopBlinking() {
    if (notificationTimer !== null) {
        clearTimeout(notificationTimer);
    }
    document.title = defaultTitle;
}

/**
 * 闪烁标题
 * @param  {[string]} m1 闪烁的信息
 * @param  {[type]} m2 默认的标题信息
 */
function blinkTitle(m1, m2) {
    document.title = m1;
    notificationTimer = setTimeout(blinkTitle, 1000, m2, m1)
}

/**
 * 发送状态信息
 */
function sendStatus() {
    var statusText = document.getElementById("statusText").value;
    sendString(statusText);
}

/**
 * 封装一个向聊天小部件页面发送通知的函数,绑定点击事件。
 */
function loadDemo() {
    document.getElementById("sendButton").addEventListener("click", sendStatus, true);
    document.getElementById("stopButton").addEventListener("click", stopBlinking, true);
    sendStatus();//页面加载立即调用,马上发送
}
/**
 * 为window绑定load加载事件和message消息事件监听器
 */
window.addEventListener("load", loadDemo, true);
window.addEventListener("message", messageHandler, true);

</script>

<h1>跨域门户</h1>
<p><b>源</b>: http://127.0.0.1</p>
状态 <input type="text" id="statusText" value="Online">
<button id="sendButton">改变状态</button>
<p>
这用PostMessage发送状态更新包含在门户页面控件iframe。
</p>
<iframe id="widget" src="http://www.vserve365.com/postMessageWidget.html"></iframe>
<p>
    <button id="stopButton">停止闪烁标题</button>
</p>


远程服务器文件postMessageWidget.html

<!DOCTYPE html>
<title>聊天小部件页面</title>
<link rel="stylesheet" href="styles.css">
<script>

var trustedOrigin = "http://127.0.0.1";

// TODO 可以添加多个白名单[数组]

/**
 * 消息事件是一个拥有data(数据)和origin(源)属性的DOM事件。data属性是发送方传递的时间消息,而origin属性是发送来源。有了origin属性,接收方能轻易地忽略掉来自不可信源的消息:根据可信源的列表能方便地判断来源是否可靠。
 */
function messageHandler(e) {
    if (e.origin === "http://127.0.0.1") {
        document.getElementById("status").textContent = e.data;
    } else {
        // 忽视来自其他源的消息
    }
}

/**
 * 编写用于与门户通信的函数。在接收到新消息时,部件将请求门户页面通知用户,并且用postMessage()函数向门户页面发送消息
 */
function sendString(s) {
    window.top.postMessage(s, trustedOrigin);//最外层的窗口
}

/**
 * 封装一个向门户页面发送通知的函数,绑定点击事件。
 */
function loadDemo() {
    document.getElementById("actionButton").addEventListener("click",
        function() {
            var messageText = document.getElementById("messageText").value;
            sendString(messageText);
        }, true);

}

/**
 * 为window绑定load加载事件和message消息事件监听器
 */
window.addEventListener("load", loadDemo, true);
window.addEventListener("message", messageHandler, true);

</script>
<h1>小部件iframe</h1>
<p><b>源</b>: http://127.0.0.1</p>
<p>状态设置: <strong id="status"></strong>(来自于门户).<p>

<div>
    <input type="text" id="messageText" value="聊天小部件的通知信息">
    <button id="actionButton">发送通知</button>
</div>

<p>
这将要求门户通知用户。门户通过闪烁标题来实现这一点。如果消息来自于HTTP之外的源代码,例如.NET 9999,门户页面将忽略它。
</p>
运行效果截图:

结束语:在处理跨源通信的消息时,一定要验证每个消息的源。此外,处理消息中的数据时也应该谨慎。即使消息来源可信源,也应该像对待外部输入时一样仔细。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值