我有严格的要求,只允许登录用户在一个选项卡中打开我的网络应用程序。我注意到 WhatsApp 和 Google Messenger 的网络应用程序已经实现了这一点。例如,尝试在多个选项卡中打开这些应用程序(无论是在同一浏览器、不同浏览器,甚至不同设备上)都会导致以下警告:
有人知道这是怎么做到的吗?服务器和客户端之间必须进行某种同步,以确保仅打开一个选项卡。但这需要一个唯一的选项卡标识符,可靠地构建它会变得相当复杂。有人知道 WhatsApp 和 Google Messenger 是如何做到这一点的吗?他们的技术似乎完美无缺。
我不知道 WhatsApp 和 Google Messenger 到底是如何做到这一点的,但是如果您使用 WebSockets(您的帖子有标签“websocket”,所以我假设您这样做)每个选项卡都有与服务器的单个连接,如果您的用户需要登录,您可以检查用户是否已经与您的服务器建立了开放的 webosket 连接。
我不知道什么是whatsApp web或google messages,但我已经设法使用本地存储来标记选项卡,并且我使用存储侦听器来监听本地存储是否有任何更改,这些代码会发生什么要做的就是决定第一个选项卡要做什么。
首先为具有唯一 id 的选项卡分配一些键,我使用 rand 函数。
localStorage.initPage = rand();
它将在本地存储中创建一个名为“initPage”的键,然后添加存储侦听器,它将检测新选项卡是否正在创建新的“initPage”键
window.addEventListener('storage', function (e) {
if (e.key === "initPage") {
// action
}
}, false);
希望有帮助。
这是我的解决方案。我会将第一个选项卡作为主选项卡,它将侦听任何新选项卡的创建并立即向它们发送关闭消息。
如果一个选项卡打开并且在 500 毫秒后没有收到关闭消息,它将把自己设置为主选项卡。
export class WindowMonitor {
tabId: string = '';
closing: boolean = false;
keepOneTab() {
this.tabId = rand();
localStorage.setItem('@tab:' + this.tabId, 'open');
window.addEventListener('storage', this.closeSelf.bind(this));
setTimeout(() => {
if (this.closing) {
return;
}
window.removeEventListener('storage', this.closeSelf.bind(this));
// Listen new tab and close them
window.addEventListener('storage', (e) => {
const key = e.key || '';
const id = key.split(':').pop();
if (id !== this.tabId && e.newValue === 'open') {
// Send close message
localStorage.setItem(key, 'close');
}
});
}, 500);
}
closeSelf(e: StorageEvent) {
const key = e.key || '';
const id = key.split(':').pop();
if (id === this.tabId && e.newValue === 'close') {
localStorage.removeItem(key);
this.closing = true;
alert('There is an active browser tab, this page will auto close.');
window.close();
}
}
}