如何检测用户是否在同一会话中打开了多个窗口或选项卡

How to detect if user has open more than one window or tab on the same session?

本文关键字:选项 窗口 会话 检测 何检测 用户 是否      更新时间:2023-09-26

我想检测用户是否在同一会话上打开了多个窗口或选项卡,如果他打开了,我想在屏幕上打印一个特殊信息。

这个限制应该只适用于一个特殊的URL,所以如果用户打开了两个带有URL的选项卡/窗口:http://page.com/limite.htm-我想打印特殊信息。当用户打开两个带有url的窗口/选项卡时:http://page.com/limite.htm和http://page.com/index.htm-一切都很好,我不会透露任何信息。

有可能吗?谢谢

我认为最好的方法是使用localStorage。http://www.gwtproject.org/doc/latest/DevGuideHtml5Storage.html

从链接,关于localStorage:

其他窗口/选项卡的可用性:在运行相同web应用的浏览器的每个窗口和选项卡上共享

因此,您可以在选项卡/窗口打开时设置一个条目,并在关闭时对其进行更改。当另一个选项卡/窗口打开时,首先检查该条目值。

显然,您需要小心:例如,浏览器崩溃可能不会触发"关闭"部分,因此用户将无法打开新选项卡,即使没有打开(localStorage仍然存在!)。如果您有服务器会话,您可以要求用户再次登录(或再次运行身份验证进程),并重置此值。您也可以尝试使用sessionStorage条目来跟踪此类问题。从链接,关于会话存储:

持久性:仅在其原始窗口或选项卡存在的时间内生存。

此外,还有一种名为"跨窗口消息传递"的功能,允许您在选项卡之间进行通信,但请检查您想要支持的浏览器是否支持它。

http://ajaxian.com/archives/cross-window-messaging-with-html-5-postmessage

我今天也做了类似的事情。我希望这能有所帮助。

// helper function to set cookies
function setCookie(cname, cvalue, seconds) {
    var d = new Date();
    d.setTime(d.getTime() + (seconds * 1000));
    var expires = "expires="+ d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
// helper function to get a cookie
function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for(var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}
// Do not allow multiple call center tabs
if (~window.location.hash.indexOf('#admin/callcenter')) {
    $(window).on('beforeunload onbeforeunload', function(){
        document.cookie = 'ic_window_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
    });
    function validateCallCenterTab() {
        var win_id_cookie_duration = 10; // in seconds
        if (!window.name) {
            window.name = Math.random().toString();
        }
        if (!getCookie('ic_window_id') || window.name === getCookie('ic_window_id')) {
            // This means they are using just one tab. Set/clobber the cookie to prolong the tab's validity.
            setCookie('ic_window_id', window.name, win_id_cookie_duration);
        } else if (getCookie('ic_window_id') !== window.name) {
            // this means another browser tab is open, alert them to close the tabs until there is only one remaining
            var message = 'You cannot have this website open in multiple tabs. ' +
                'Please close them until there is only one remaining. Thanks!';
            $('html').html(message);
            clearInterval(callCenterInterval);
            throw 'Multiple call center tabs error. Program terminating.';
        }
    }
    callCenterInterval = setInterval(validateCallCenterTab, 3000);
}

LocalStorage无法跨协议工作,因此,如果用户在一个选项卡中使用http打开网站,在另一个选项卡上使用https打开网站,那么这两个选项卡都将看到单独的LocalStorage对象。Cookie没有同样的问题(它们还有其他问题,例如,夸大每个返回到您网站的http请求的大小)

下面的示例代码维护了一个映射,其中键是一个唯一的浏览器选项卡标识符,值是一个时间戳,指示该选项卡上次确认它仍然打开的时间。地图存储在cookie中。这不是一个完美的方法——每个选项卡每3秒更新一次,而不是立即更新,而且有竞争条件(多个选项卡更新同一个cookie),但取决于你想要什么,这可能会奏效。

如果你只在一个特定的页面上运行这段代码,你就会(或多或少)知道该页面何时在同一浏览器中多次打开。或者在你网站的每一页上运行它,并知道你的网站何时在多个选项卡中打开。

为了简洁起见,省略了Cookie读取/写入代码(但取自https://stackoverflow.com/a/24103596/4486628),并且为了简单起见,cookie中的数据编码是用json完成的,但您已经明白了。

如果您运行此代码并使用FireBug的cookie选项卡查看cookie,您可以看到cookie在选项卡打开和关闭时进行更新。实际上,当多个选项卡打开时提醒用户之类的事情留给读者做练习。

var timePeriod = 3000; // 3 seconds
function tabHandler() {
    // ensure the current window has an identifier set
    if (!window.name.match(/^MySite[0-9]{3}/)) {
        window.name = 'MySite' + Math.round(Math.random() * 1000);
    }
    // read in the state of all the tabs
    var tabCookie = readCookie('tabs') || null;
    var tabs = JSON.parse(tabCookie) || {};
    // update the timestamp for the current tab
    var now = (new Date()).getTime();
    tabs[window.name] = now;
    // remove tab details that haven't had their timestamp updated
    var tooOld = timePeriod * 2;
    for (var tabKey in tabs) {
        if ((now - tabs[tabKey]) > tooOld) {
            delete tabs[tabKey];
        }
    }
    // write back the current state of tabs
    createCookie('tabs', JSON.stringify(tabs), 1);
    setTimeout(tabHandler, timePeriod);
}
setTimeout(tabHandler, timePeriod);