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

时间:2015-04-07 07:53:22

标签: javascript

我想检测用户是否在同一会话中打开了多个窗口或标签,如果他这样做了 - 我想在屏幕上打印一个特殊信息。

此限制只应在一个特殊URL中使用,因此如果用户打开了两个带有URL的标签/窗口:http://page.com/limite.htm - 我想打印特殊信息。当用户打开两个带有网址的窗口/标签时:http://page.com/limite.htmhttp://page.com/index.htm - 一切正常,我也不会显示任何信息。

有可能吗? 感谢。

3 个答案:

答案 0 :(得分:3)

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

从链接中了解localStorage:

  

其他Windows /标签的可用性:在运行相同网络应用的一个浏览器的每个窗口和标签中共享

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

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

  

持久性:只有在其原始窗口或标签页中生存。

此外,还有一些名为" Cross window messaging",允许您在标签之间进行通信,但请检查您要支持的浏览器是否支持。

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

答案 1 :(得分:2)

我今天做的事非常相似。我希望这会有所帮助。

// 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);
}

答案 2 :(得分:1)

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);