标签或窗口之间的通讯

2020/10/21 00:02 · javascript ·  · 0评论

我正在寻找一种方法,如何在浏览器中的多个选项卡或窗口之间进行通信(在同一域中,而不是在CORS上)而不会留下痕迹。有几种解决方案:

  1. 使用窗口对象
  2. postMessage
  3. 饼干
  4. 本地存储

第一个可能是最糟糕的解决方案-您需要从当前窗口中打开一个窗口,然后您只能在保持窗口打开状态下进行通信。如果您在任何窗口中重新加载页面,则很可能会丢失通信。

使用postMessage的第二种方法可能启用了跨域通信,但是遇到了与第一种方法相同的问题。您需要维护一个窗口对象。

第三种方式,使用cookie,将一些数据存储在浏览器中,这实际上看起来像是向同一域中的所有窗口发送消息,但是问题在于您永远无法知道所有选项卡之前是否都已经读取了“消息”打扫干净。您必须实现某种超时才能定期读取Cookie。此外,您受到最大Cookie长度(4KB)的限制。

第四个解决方案,使用localStorage,似乎克服了cookie的局限性,甚至可以监听事件。可接受的答案中描述了如何使用它。

编辑2018:可接受的答案仍然有效,但是对于现代浏览器,有一个更新的解决方案可以使用BroadcastChannel。请参阅其他答案,以获取一个简单的示例,该示例描述了如何使用BroadcastChannel轻松在选项卡之间传输消息。

编辑2018年:您可以更好地为此目的使用BroadcastChannel,请参阅下面的其他答案。但是,如果您仍然希望使用本地存储在选项卡之间进行通信,请按照以下方式进行操作:

为了在某​​个选项卡向其他选项卡发送消息时获得通知,您只需要在“存储”事件上进行绑定。在所有标签中,执行以下操作:

$(window).on('storage', message_receive);

message_receive每次在任何其他选项卡中设置localStorage的任何值时,都会调用该函数事件监听器还包含新设置为localStorage的数据,因此您甚至不需要解析localStorage对象本身。这非常方便,因为您可以在设置值后立即重置该值,以有效清除任何痕迹。这是消息传递功能:

// use local storage for messaging. Set message in local storage and clear it right away
// This is a safe way how to communicate with other tabs while not leaving any traces
//
function message_broadcast(message)
{
    localStorage.setItem('message',JSON.stringify(message));
    localStorage.removeItem('message');
}


// receive message
//
function message_receive(ev)
{
    if (ev.originalEvent.key!='message') return; // ignore other keys
    var message=JSON.parse(ev.originalEvent.newValue);
    if (!message) return; // ignore empty msg or msg reset

    // here you act on messages.
    // you can send objects like { 'command': 'doit', 'data': 'abcd' }
    if (message.command == 'doit') alert(message.data);

    // etc.
}

因此,现在,一旦您的选项卡绑定了onstorage事件,并且您实现了这两个功能,就可以简单地将消息广播到其他选项卡调用,例如:

message_broadcast({'command':'reset'})

请记住,两次发送完全相同的消息只会传播一次,因此,如果您需要重复发送消息,请向它们添加一些唯一的标识符,例如

message_broadcast({'command':'reset', 'uid': (new Date).getTime()+Math.random()})

还要记住,广播消息的当前选项卡实际上并没有收到,只有同一域中的其他选项卡或窗口才收到。

您可能会问,如果用户在setItem()调用之后,在removeItem()之前加载了另一个网页或关闭了他的选项卡,将会发生什么情况。好吧,根据我自己的测试,浏览器将保持卸载状态,直到整个功能message_broadcast()完成。我测试过要放置很长的for()周期,但在关闭之前它仍然等待周期结束。如果用户只是杀死它们之间的选项卡,那么浏览器将没有足够的时间将消息保存到磁盘,因此在我看来,这种方法是一种安全的方法,它可以毫无痕迹地发送消息。欢迎发表评论。

有专门用于此目的的现代API-广播频道

就像这样简单:

var bc = new BroadcastChannel('test_channel');

bc.postMessage('This is a test message.'); /* send */

bc.onmessage = function (ev) { console.log(ev); } /* receive */

消息不必只是DOMString,可以发送任何类型的对象。

除了API的简洁性外,这大概是该API的主要优点-无需对象字符串化。

当前仅在Chrome和Firefox中受支持,但是您可以找到使用localStorage的polyfill。

对于那些寻找不基于jQuery的解决方案的人,这是Thomas M提供的解决方案的纯JavaScript版本:

window.addEventListener("storage", message_receive);

function message_broadcast(message) {
    localStorage.setItem('message',JSON.stringify(message));
}

function message_receive(ev) {
    if (ev.key == 'message') {
        var message=JSON.parse(ev.newValue);
    }
}

结帐AcrossTabs -跨域浏览器标签页之间容易沟通。它结合使用了postMessagesessionStorage API,使通信更加轻松和可靠。


有不同的方法,每种方法都有其优点和缺点。让我们讨论每个:

  1. 本地存储

    优点

    1. Web存储可以简单地视为对cookie的一种改进,从而提供了更大的存储容量。如果您查看Mozilla的源代码,我们可以看到5120KB5MB在Chrome上等于250万个字符)是整个域的默认存储大小。与典型的4KB Cookie相比,这为您提供了更多的处理空间。
    2. 不会针对每个HTTP请求(HTML,图像,JavaScript,CSS等)将数据发送回服务器,从而减少了客户端与服务器之间的通信量。
    3. 存储在localStorage中的数据将一直保留到明确删除为止。所做的更改将被保存,并且可用于当前和将来对该站点的所有访问。

    缺点

    1. 它适用于同源策略因此,存储的数据只能在相同的来源上使用。
  2. 饼干

    优点:

    1. 与其他人相比,没有AFAIK。

    缺点:

    1. 4K限制适用于整个cookie,包括名称,值,有效期限等。要支持大多数浏览器,请将该名称保留在4000字节以下,并将cookie的整体大小保留在4093字节以下。
    2. 每个HTTP请求(HTML,图像,JavaScript,CSS等)会将数据发送回服务器,从而增加了客户端与服务器之间的通信量。

      通常,允许以下操作:

      • 总共300个Cookie
      • 每个Cookie 4096个字节
      • 每个域20个Cookie
      • 每个域81920字节(给出20个最大大小为4096的cookie = 81920字节。)
  3. sessionStorage

    优点:

    1. 它类似于localStorage
    2. 更改仅适用于每个窗口(或Chrome和Firefox等浏览器中的标签)。所做的更改将被保存,并且可用于当前页面,以及以后在同一窗口上对该站点的访问。关闭窗口后,将删除存储

    缺点:

    1. 数据仅在设置它的窗口/选项卡内可用。
    2. 数据不是持久性的,即一旦关闭窗口/选项卡,它将丢失。
    3. localStoragett一样适用于同源政策因此,存储的数据只能在相同的来源上使用。
  4. 留言

    优点:

    1. 安全地启用跨域通信。
    2. 作为数据点,WebKit实现(由Safari和Chrome使用)目前不强制执行任何限制(内存不足导致的限制除外)。

    缺点:

    1. 需要从当前窗口打开一个窗口,然后仅在保持窗口打开的情况下才能进行通信。
    2. 安全问题-通过postMessage发送字符串是您将拾取其他JavaScript插件发布的其他postMessage事件,因此请确保对targetOrigin传递给消息侦听器的数据实施和完整性检查。
  5. PostMessage + SessionStorage的组合

    使用postMessage在多个选项卡之间进行通信,并同时在所有新打开的选项卡/窗口中使用sessionStorage来保持传递的数据。只要选项卡/窗口保持打开状态,数据就会保留下来。因此,即使关闭了打开器的选项卡/窗口,即使刷新后打开的选项卡/窗口也将具有全部数据。

我为此编写了一个名为AcrossTabs的JavaScript库,该库使用postMessage API在跨域标签/窗口和sessionStorage之间进行通信,以持久保存打开的标签/窗口的身份,只要它们存在即可。

人们应该考虑使用的另一种方法是共享工作者。我知道这是一个最先进的概念,但是您可以在Shared Worker上创建一个中继,该中继的速度比localstorage快得多,并且只要您位于同一原点,就不需要父/子窗口之间的关系。

有关我对此所做的一些讨论,请参见此处答案

有一个很小的开源组件可以在相同来源的标签/窗口之间进行同步/通信(免责声明-我是其中的一员!)localStorage

TabUtils.BroadcastMessageToAllTabs("eventName", eventDataString);

TabUtils.OnBroadcastMessage("eventName", function (eventDataString) {
    DoSomething();
});

TabUtils.CallOnce("lockname", function () {
    alert("I run only once across multiple tabs");
});

https://github.com/jitbit/TabUtils

PS我在这里推荐它是自由的,因为当事件几乎同时发生时,大多数“锁定/互斥/同步”组件在websocket连接上失败

我创建了一个库sysend.js,它很小,您可以检查其源代码。该库没有任何外部依赖项。

您可以将其用于同一浏览器和域中的选项卡/窗口之间的通信。该库使用BroadcastChannel(如果支持)或localStorage中的存储事件。

API非常简单:

sysend.on('foo', function(message) {
    console.log(message);
});
sysend.broadcast('foo', {message: 'Hello'});
sysend.broadcast('foo', "hello");
sysend.broadcast('foo'); // empty notification

当您的浏览器支持BroadcastChannel时,它将发送文字对象(但实际上它是由浏览器自动序列化的),如果没有,则首先将其序列化为JSON,然后在另一端反序列化。

最新版本还具有帮助程序API,用于创建跨域通信的代理。(它需要目标域上的单个html文件)。

这是演示

编辑

如果您在目标域上包含特殊文件并从源域调用函数,则新版本还支持跨域通信proxy.htmlproxy

sysend.proxy('https://target.com');

(proxy.html这是一个非常简单的html文件,该库中只有一个script标签)。

如果要双向通信,则需要在target.com上进行相同的通信

注意:如果您将使用localStorage实现相同的功能,则IE中存在问题。存储事件被发送到同一窗口,该窗口触发了该事件,对于其他浏览器,仅针对其他选项卡/窗口调用该事件。

我创建了一个模块,该模块的功能与官方的Broadcastchannel相同,但具有基于localstorage,indexeddb和unix-sockets的后备功能。这样可以确保即使在Webworkers或NodeJS上也可以正常使用。参见pubkey:BroadcastChannel

这是Tomas M Chrome答案的开发storage部分我们必须添加监听器

window.addEventListener("storage", (e)=> { console.log(e) } );

在存储中加载/保存项目不会引发此事件-我们必须通过以下方式手动触发它

window.dispatchEvent( new Event('storage') ); // THIS IS IMPORTANT ON CHROME

现在,所有打开的标签页都会收到事件

我在我的博客上写了一篇文章:http : //www.ebenmonney.com/blog/how-to-implement-remember-me-functionality-using-token-based-authentication-and-localstorage-in-a-网络应用程序

使用我创建的库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

还有其他方便的方法也可以处理其他情况

本文地址:http://javascript.askforanswer.com/biaoqianhuochuangkouzhijiandetongxun.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!