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

9
我希望检测用户是否在同一会话中打开了多个窗口或选项卡,如果是,我想在屏幕上打印特殊信息。这种限制仅适用于一个特定的URL,因此如果用户已经打开了两个包含以下URL的选项卡/窗口:http://page.com/limite.htm - 我想打印特殊信息。当用户同时打开两个包含以下URL的窗口/选项卡:http://page.com/limite.htmhttp://page.com/index.htm 时 - 一切正常,我不会显示任何信息。这种情况是否可能?谢谢。

套接字是我想到的唯一“安全”的东西。当然,可能有点过头了。不过问题很好。 - Sharky
1
请查看以下内容:https://dev59.com/gmct5IYBdhLWcg3wsPZ5 - Vikrant
你能给我一些例子吗? - Newester
这是可能的,而且有几种方法。你的问题中只有一个JavaScript标签,所以你是在寻找仅使用JavaScript的解决方案吗? - atmd
@atmd,不,我可以使用其他的东西。 - Newester
3个回答

4

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

从链接中了解到localStorage:

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

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

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

持久性:只在其源窗口或标签页存在期间存活。

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

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


链接已失效,请查看Internet Archive缓存版本。 https://web.archive.org/web/20200615143322/http://ajaxian.com/archives/cross-window-messaging-with-html-5-postmessage - Rikijs

3

我今天做了类似的事情。希望这可以帮到你。

// 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打开,这两个标签页将看到不同的本地存储对象。Cookie没有同样的问题(它们有其他问题,例如每个http请求回到您的网站时会膨胀大小)

下面的示例代码维护了一个映射,其中键是唯一的浏览器标识符,值是指示该标签上次确认其仍然打开的时间戳。该映射存储在一个cookie中。这不是一个完美的方法 - 每个标签页每3秒更新一次自身而不是立即更新,并且存在竞争条件(多个标签页更新相同的cookie),但根据您的需求,这可能会解决问题。

如果您只在特定页面上运行此代码,则(或多或少)知道该页面在同一浏览器中是否打开了多次。或者在您网站的每个页面上运行它,并知道您的网站在多个标签页中打开的情况。

为简洁起见,省略了cookie读取/写入代码(但从https://dev59.com/hWUq5IYBdhLWcg3wV_Ei#24103596中获取),并且使用json对cookie中的数据进行编码以简化操作,但您已经了解了思路。

如果您运行此代码并使用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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接