如何检测浏览器关闭?

时间:2008-11-18 18:31:28

标签: javascript servlets

在我的网络应用程序中,当用户登录时,我将他的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中是否有任何其他方法在会话关闭时被调用?

6 个答案:

答案 0 :(得分:13)

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

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

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

答案 1 :(得分:7)

我建议你在Servlet引擎破坏会话时删除ID。注册HttpSessionListener,在调用sessionDestroyed()时删除用户的ID。

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:2)

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

答案 4 :(得分:2)

我最近必须这样做,经过一些搜索后,我在网上找到了一些解决方案......所有这些解决方案都不能普及!

onbeforeclose和onclose事件用于此任务。但有两个捕获:当用户重新加载页面或甚至只是更改当前页面时它们被触发。有一些技巧可以看看事件是否真的是一个窗口/页面/标签关闭(看一些Dom属性在关闭事件时变得混乱),但是:

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

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

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

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

答案 5 :(得分:0)

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

向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.