我正在寻找一种方法,如何在浏览器中的多个选项卡或窗口(在同一域上,而不是CORS)之间进行通信而不留下痕迹。有几种解决方案:
使用window对象
postMessage
饼干
localStorage
第一种可能是最糟糕的解决方案——您需要从当前窗口打开一个窗口,然后您只能在保持窗口打开的情况下进行通信。如果在任何窗口中重新加载页面,很可能会失去通信。
第二种方法(使用postMessage)可能支持跨源通信,但它遇到了与第一种方法相同的问题。您需要维护一个窗口对象。
第三种方法是使用cookie,在浏览器中存储一些数据,这实际上看起来像是向同一域上的所有窗口发送消息,但问题是,在清理之前,您永远无法知道所有选项卡是否已经阅读了“消息”。您必须实现某种类型的超时来定期读取cookie。此外,您还受到最大cookie长度(4 KB)的限制。
第四种解决方案,使用localStorage,似乎克服了cookie的限制,甚至可以使用事件监听。如何使用它在公认的答案中有描述。
我在我的博客上写过一篇文章:跨浏览器选项卡共享sessionStorage数据。
使用一个库,我创建了storageManager。你可以通过以下方法实现:
storageManager.savePermanentData('data', 'key'): //saves permanent data
storageManager.saveSyncedSessionData('data', 'key'); //saves session data to all opened tabs
storageManager.saveSessionData('data', 'key'); //saves session data to current tab only
storageManager.getData('key'); //retrieves data
还有其他方便的方法来处理其他场景。
有一个基于localStorage的小开源组件,可以在相同来源的选项卡/窗口之间同步和通信(免责声明-我是贡献者之一!)
TabUtils.BroadcastMessageToAllTabs("eventName", eventDataString);
TabUtils.OnBroadcastMessage("eventName", function (eventDataString) {
DoSomething();
});
TabUtils.CallOnce("lockname", function () {
alert("I run only once across multiple tabs");
});
注:我冒昧地在这里推荐它,因为当事件几乎同时发生时,大多数“锁/互斥/同步”组件在websocket连接上失败。
我创建了一个syend .js库,用于在浏览器选项卡和窗口之间发送消息。该库没有任何外部依赖项。
您可以使用它在同一浏览器和域中的选项卡/窗口之间进行通信。该库使用BroadcastChannel(如果支持)或localStorage中的存储事件。
API非常简单:
sysend.on('foo', function(data) {
console.log(data);
});
sysend.broadcast('foo', {message: 'Hello'});
sysend.broadcast('foo', "hello");
sysend.broadcast('foo', ["hello", "world"]);
sysend.broadcast('foo'); // empty notification
当您的浏览器支持BroadcastChannel时,它会发送一个文本对象(但实际上是由浏览器自动序列化的),如果不支持,则先将其序列化为JSON,然后在另一端反序列化。
最新版本还提供了一个帮助API,用于创建跨域通信的代理(它需要目标域上的单个HTML文件)。
这里是一个演示。
新版本也支持跨域通信,如果你在目标域中包含一个特殊的proxy.html文件,并从源域中调用代理函数:
sysend.proxy('https://target.com');
(proxy.html是一个非常简单的HTML文件,它只有一个带有库的脚本标记)。
如果你想要双向通信,你需要在其他域上做同样的事情。
注意:如果您将使用localStorage实现相同的功能,则Internet Explorer中存在一个问题。存储事件被发送到相同的窗口,这触发了事件,对于其他浏览器,它只被其他选项卡/窗口调用。