16

在我的网络应用程序中,当用户登录时,我将他的 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 ]
...

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

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

4

6 回答 6

14

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

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

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

于 2008-11-18T18:47:58.500 回答
7

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

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

于 2008-11-18T18:37:05.107 回答
3

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

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

于 2008-11-18T18:36:30.643 回答
2

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

于 2008-11-18T18:47:32.527 回答
2

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

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

  • 它们依赖于浏览器
  • 这些技巧没有记录,因此很脆弱
  • 实际上它们随着浏览器版本/更新而变化......

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

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

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

于 2008-11-18T21:15:47.220 回答
-1

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

向 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.
于 2013-04-11T20:08:35.160 回答