【问题标题】:How to detect if user has open more than one window or tab on the same session?如何检测用户是否在同一会话中打开了多个窗口或选项卡?
【发布时间】:2015-06-11 18:02:01
【问题描述】:

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

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

有可能吗? 谢谢。

【问题讨论】:

  • sockets 是我想到的唯一安全的东西。当然,矫枉过正。很好的问题
  • 你能给我一些例子吗?
  • 这是可能的,并且有几种方法。您的问题中只有一个 javascript 标签,所以您是否正在寻找一个仅 javacript 的解决方案?
  • @atmd,不,我可以使用其他任何东西。

标签: javascript


【解决方案1】:

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

// 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】:

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

    【讨论】:

      【解决方案3】:

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

      来自链接,关于localStorage:

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

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

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

      持久性:仅在其原始窗口或选项卡中存在。

      此外,还有一种叫做“跨窗口消息传递”的东西,它允许您在选项卡之间进行通信,但请检查您想要支持的浏览器是否支持它。

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

      【讨论】:

        猜你喜欢
        • 2011-07-31
        • 1970-01-01
        • 2013-04-01
        • 1970-01-01
        • 2017-06-28
        • 1970-01-01
        • 2015-12-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多