【问题标题】:destroy session on window close?关闭窗口时销毁会话?
【发布时间】:2010-10-31 20:57:28
【问题描述】:

我在 php 中创建了一个具有注销功能等的登录系统。但我需要在窗口关闭时销毁会话。这需要“即时”或尽快将用户状态更改为离线。我真的不想在会话上设置时间,因为这对于必须一直登录的用户来说很烦人。

欢迎提出任何建议,谢谢。 =)

【问题讨论】:

    标签: php


    【解决方案1】:

    默认情况下,当浏览器关闭时,PHP 发送的所有会话 cookie 都会被删除。但据我所知,您想在其他浏览器上显示通知。这有点难,而且不太好。您必须使用window.onclose 事件处理程序并向服务器发出Ajax 请求(我相信它应该是一个同步请求)以发出窗口关闭的信号。而且同步调用也不是很好......

    另一方面,其他浏览器将不得不通过其他 Ajax 请求拉取服务器,以查看某个用户何时注销。

    所有这些 Ajax 请求都构成了一个丑陋的解决方案。

    更新:

    正如 Thorarin 和 Jonathan Fingland 所说,多个窗口可能存在问题(不是选项卡,因为 window.onclose 会在窗口而不是选项卡上触发),但我相信这个问题也有解决方案。如果第一个窗口设置了一个 cookie number_of_windows = 1,每个打开的窗口都会递增,然后在窗口关闭时,仅当 number_of_windows 等于 1 时才会触发 Ajax 请求,否则它只会递减 number_of_windows

    更新 2:

    上述解决方案确实会在打开多个标签时遇到问题。我正在考虑如何缓解。

    更新 3:

    好的,我想出了某种解决方案,但它在 IE6 中不起作用,不知道其他 IE 版本。下面的 sn-p 跟踪打开的窗口和选项卡的数量(IE 除外,它不会在窗口之间实时更新 document.cookie,但我相信它可以通过一些 IE 专有功能来解决)。然后在每个页面卸载时,这意味着即使在同一个网站上从一个页面导航到另一个页面,脚本也会检查有多少打开的窗口。如果它是唯一打开的窗口/选项卡,那么它会发出 Ajax 请求。这是解决方案的第一部分。现在,第二部分。

    在服务器端,Ajax 调用所请求的脚本应该更新数据库中的一些条目,说明用户可能已经关闭了页面。您如何判断她是否只是在访问您网站上的新页面?很简单,在每次访问页面时,您都会检查数据库中该会话的“可能已注销”值,如果将它们标记为假(用户已登录),否则用户会一直在数据库中注销(真标志)。

    这很混乱,但这是我想到的唯一解决方案,因为我无法确定 JavaScript 中的页面重新加载等。另外,我没有做广泛的测试,更多的是一个想法。无论如何,我不会推荐这个解决方案。对每个更改页面的 Ajax 请求都是多余的,实际上会使服务器上的点击量翻倍,而不计算其他浏览器完成的轮询。

    这里是sn-p。顺便说一下, bakery.js 是 document.cookie 的一个小包装器。你可以找到its source here on github

    <!DOCTYPE html>
    
    <html>
    <head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="bakery.js"></script>
    <script type="text/javascript">
    var logout = function() {
        var xhr = new XMLHttpRequest;
        xhr.open("GET", "logout.php", false);
        xhr.send(null);
    };
    
    window.onload = function() {
        var winNumber = parseInt(IGS.Bakery.getCookie("winNumber"), 10) || 0;
        IGS.Bakery.setCookie("winNumber", winNumber + 1);
    };
    
    window.onunload = function() {
        var winNumber = parseInt(IGS.Bakery.getCookie("winNumber"), 10) || 0;
        IGS.Bakery.setCookie("winNumber", winNumber - 1);
    
        if (winNumber === 1) {
            logout();
        }
    };
    
    var showCookies = function() {
        alert(IGS.Bakery.getCookie("winNumber"));
    };
    </script>
    </head>
    <body>
    
    <a href="#" onclick="showCookies();">show</a>
    
    </body>
    </html>
    

    忘了说。 window.onclose 不是跨浏览器。

    【讨论】:

    • 也不能像 thorarin 的示例中所指出的那样可靠地工作,因为可以在同一个站点上打开多个窗口/选项卡。第一个关闭将导致会话被终止
    • @Jonathan Fingland,我用一个潜在的解决方案更新了我的答案。等待反馈。
    • 会有示例代码来做到这一点吗?因为我不完全了解如何设置窗口 cookie 的数量。再次感谢
    • @Elliott,刚刚发布了某种解决方案。但答案基本上是不可能的。
    • 非常感谢,一定有什么办法吗?当用户关闭浏览器时,Facebook 等网站如何处理?
    【解决方案2】:

    您可以使用 JavaScript 来实现 OnUnload 事件,并使用 AJAX 来传达离开网站的用户。但是,当他们导航到另一个页面时也会发生该事件。你必须实现类似“如果用户在 x 秒内没有请求新页面”,他已经离开了我的网站,但如果你考虑到打开多个窗口的可能性,它永远不会可靠地工作。

    做到这一点的唯一方法是定期将 AJAX 回发到用户仍在您的页面上的服务器。但它仍然不会是即时的。

    您可以尝试使用您要发回的脚本进行试验。在响应之前建立一个重要的等待期。当用户离开您的页面时,浏览器可能会中止正在进行的 XmlHttpRequest。您的服务器端脚本可以注册客户端断开连接并得出用户已经离开的结论......再次,除非他们继续加载另一个页面。

    简而言之,没有明确的方法可以以干净的方式做到这一点。

    【讨论】:

    • 好的,谢谢,这给了我一个更好的主意,我不认为会有“简单的方法”。
    【解决方案3】:

    您可以将“显示为已登录”的概念与实际登录分开。例如,每次用户请求一个页面时,您可以将其标记为“在线”再过几分钟,但您可以设置他们的实际登录超时到几个小时。在这个方案中,如果用户离开他们的计算机,网站会在几分钟后将他们显示为“离线”,但他们仍然可以在一个小时左右后返回,而不必重新登录。

    【讨论】:

      猜你喜欢
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-17
      • 1970-01-01
      • 2023-03-24
      • 2013-03-24
      • 2017-10-13
      相关资源
      最近更新 更多