【问题标题】:How to detect browser closing?如何检测浏览器关闭?
【发布时间】:2008-11-18 18:31:28
【问题描述】:

在我的网络应用程序中,当用户登录时,我将他的 Id 添加到 servlet 中的有效 Id 向量中,当他注销时,我从向量中删除他的 Id,这样我就可以看到有多少当前用户活动,如果用户忘记注销,我的servelt生成的html有:

<meta http-equiv="Refresh" content="30; url=My_Servlet?User_Action=logout&User_Id=1111">

在标签中自动将他注销。

但我注意到许多用户永远在那里,从未退出过。我发现了为什么通过关闭他们的浏览器,他们永远不会手动或自动注销,因此他们的用户 ID 永远不会从有效的用户 ID 向量中删除。

所以,我的问题是:如何检测用户关闭浏览器,以便我的 servlet 可以从向量中删除他们的 Id?


我在隧道尽头看到了一些亮光,但还有一个问题,我的程序有这样的东西:

活跃用户列表:

User_1 : Machine_1 [ IP_1 address ]
User_2 : Machine_2 [ IP_2 address ]
User_3 : Machine_3 [ IP_3 address ]
...

我如何从会话侦听器中知道哪个用户的会话已结束并因此将他从我的列表中删除?

我希望当会话结束时,会调用 HttpServlet 的 destroy() 方法,我可以删除其中的用户 ID,但是当用户关闭浏览器时它永远不会被调用,为什么?当会话关闭时,HttpServlet 中是否还有其他方法被调用?

【问题讨论】:

    标签: javascript servlets


    【解决方案1】:

    在服务器端无法知道浏览器已关闭(除非您使用一些 JavaScript 向服务器发送消息)。怎么会有?想想 HTTP 是如何工作的 - 一切都是请求和响应。

    但是,应用程序服务器会跟踪会话何时处于活动状态,甚至会告诉您会话何时被销毁(例如由于超时)。查看this page 了解如何配置HttpSessionListener 来接收这些事件。然后,您可以简单地跟踪活动会话的数量。

    活动会话的数量将落后于当前用户的实际数量,因为在会话超时之前必须经过一段(可配置的)时间;但是,这应该有点接近(您可以降低会话超时以提高准确性)并且它比 1)自己跟踪会话或 2)在浏览器关闭时向服务器发送一些异步 JavaScript(不保证会发送)。

    【讨论】:

    • 顺便说一句 - 我不知道我链接到的代码将如何在集群/多 VM 环境中工作。我怀疑不是很好。
    • 此链接stardeveloper.com/articles/… 已损坏。更新你的答案。
    【解决方案2】:

    我建议您在 Servlet 引擎销毁会话时删除 ID。注册一个HttpSessionListener,在调用sessionDestroyed() 时删除用户ID。

    Diodeus 的想法只会帮助您更快地检测到会话结束。

    【讨论】:

      【解决方案3】:

      在 JavaScript 中,您可以使用 onbeforeclose 事件在用户关闭浏览器时将调用传回服务器。

      我通常使用同步 Ajax 调用来执行此操作。

      【讨论】:

        【解决方案4】:

        没有万无一失的方法来做你想做的事,但 sblundy 和 Diodeus 都有涵盖大多数情况的计划。对于在浏览器中关闭 Javascript、互联网连接中断或电源中断的人,您无能为力。您应该在一段时间不活动后剔除会话(我认为这是 sblundy 建议的监听会话破坏的做法)。

        【讨论】:

          【解决方案5】:

          我最近不得不这样做,经过一些搜索,我在网上找到了一些解决方案......所有这些都不能通用!

          onbeforeclose 和 onclose 事件用于此任务。但是有两个问题:当用户重新加载页面甚至只是更改当前页面时它们会被触发。有一些技巧可以查看事件是否实际上是一个窗口/页面/选项卡关闭(查看一些 Dom 属性在关闭事件时变得混乱),但是:

          • 它们取决于浏览器
          • 这些技巧没有记录,因此很脆弱
          • 实际上它们会随着浏览器版本/更新的不同而不同...

          最糟糕的是,这些事件现在被大多数现代浏览器忽略了,因为它们已被浏览器关闭时弹出窗口的流氓广告滥用。它们不会在 Safari、Opera、IE7 等中触发。

          正如所指出的,大多数具有登录功能的 Web 应用程序会在一段时间后破坏用户会话,例如。半小时。我被要求在关闭浏览器时注销以更快地释放宝贵的资源:许可证。因为用户经常忘记退出...

          我给出的解决方案是定期(比如 1 分钟)使用 Ajax 请求(发送用户 ID)ping 服务器。如果服务器在 3 分钟内没有收到 ping,它会断开用户连接。

          【讨论】:

          • 这在功能上与使用 HttpSessionListener 几乎相同,只是您必须自己编写 Ajax 和服务器端处理程序,重新发明轮子。
          • 你在开玩笑吧? HttpSessionListener 是一个接口,它不提供 Ajax 和魔法。
          【解决方案6】:

          这是完成“检测浏览器关闭”的一种肮脏方式 我在这个网站的某个论坛上找到了这个,当我再次找到它时,我会链接到它。

          向 http 响应添加额外的标头。当额外的请求进来时,它们将包含这些额外的标头。您可以检查这些标题,如果它们不存在,您可以终止会话,因此将开始一个新的。虽然这不会“通知”您浏览器是否关闭,但它可以告诉您是否有人关闭了他们的窗口并试图返回,因为您添加的标题将会丢失。

           wrapper.setHeader("Cache-Control", "no-cache, no-store, must-     revalidate");
           wrapper.setHeader("Pragma", "no-cache");
           wrapper.setDateHeader("Expires", 0);
          
           Where wrapper is a response wrapper.
          
           if (wrapper.getHeaderNames().size() < the number of headers you are expecting)
           request.getSession().invalidate();
          
           Not perfect but it might help someone.
          

          【讨论】:

          • 好吧,这并没有真正检测到浏览器关闭,它只是检测是否有人从同一个客户端返回到您的服务器,没有包含您的标头,因此它将它们发送回您的登录页面.所以这不是一个真正有价值的答案。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-06
          • 2013-05-12
          • 1970-01-01
          • 2014-02-21
          • 2012-09-11
          相关资源
          最近更新 更多