您的位置:首页 > 其它

浏览器刷新、关闭页面与统计在线人数

2016-03-28 11:21 337 查看
项目中可能需要统计在线人数,也可能需要在用户在退出时进行用户注销登录,既为统计实时在线人数,也为及时清理暂时不再使用的session,节约资源提高性能。

对于以上的情况,若用户使用页面的注销按钮退出登录,那一定万事大吉了。当实际中这种可能性很小的,直接关闭浏览器标签或整个浏览器以及其他意外情况都可能是用户离开的方式。对此,首先的想到的是为这些情况绑定注销事件回调函数,在浏览器窗口关闭时执行。

一开始,也是这样干的,效果还不错,实现了我想要的效果。但没多久,同事报告了一个bug:在刷新界面后,所有数据都丢失了。于是我去解决这个bug,当时估计是session丢失了,先从前端检查刷新后是不是重新拿了新的session,然后发现并没有(可参见Servlet 中 session 的创建、销毁及监听了解更多关于session)。然后去后台查看日志,发现原来刷新之后进行了注销操作,这时大概知道问题出在何处了,注掉关闭窗口退出登录的代码。问题解决。于是深入研究了一下,于是有本文。

在刷新或关闭时会调用onbeforeunload和onunload事件,只是刷新事件最后会调用onload加载页面,之前的退出登录回调函数就绑定在onbeforeunload事件上。两者的区别在于onbeforeunload在onunload之前执行,它还可以阻止onunload的执行。onbeforeunload在准备向服务器请求新的页面,但还未开始读取时调用;而onunload则已经从服务器上读到了需要加载的新的页面,在即将替换掉当前页面时调用,其无法阻止页面的更新和关闭。

也就是说,无法单纯的调用onbeforeunload或onunload事件区分是刷新还是关闭了浏览器。

于是找到了类似下面这样的代码

//以下代码不会生效
window.onbeforeunload=function (){
alert("===onbeforeunload===");
if(event.clientX>document.body.clientWidth && event.clientY < 0 || event.altKey){
alert("你关闭了浏览器");
}else{
alert("你正在刷新页面");
}
}


但完全不起作用(至少在试验的浏览器上不起作用,故不知为什么之前会出现这个Hack技巧)。此时的event并未定义的clientX、clientY属性,也没有的pageX、pageY属性,这些属性只有在在鼠标事件时发生,而此时触发的是onbeforeunload或onunload事件。而且在关闭窗口时,无法保证两个事件会被正确的调用的,因为窗口关闭丢失了代码执行的环境。

好了,这种方法宣告失败。转念一想,我们的目标其实是区分刷新和关闭两个事件那我区分刷新事件好了。同样,刷新的方式也有很多种,一一识别出来处理就好了,于是有了下面一段代码。

$(document).ready(function() {
var isRefresh = false;
//使用快捷键刷新,F5、Ctrl+F5、Ctrl+R
$(document).keydown(function(e) {
if ((e.which || e.keyCode) == 116) {
isRefresh = true;
} else if ((e.which || e.keyCode) == 82 && e.ctrlKey) {
isRefresh = true;
} else if ((e.which || e.keyCode) == 116 && e.ctrlKey) {
isRefresh = true;
}
});
//鼠标右键刷新
$(document).mousedown(function(e) {
switch ((e.which || e.keyCode)) {
case 3:
isRefresh = true;
break;
default:
isRefresh = false;
break;
}

//可是怎么屏蔽工具栏的刷新按钮呢???

$(window).on('beforeunload', function() {
if (isRefresh) {
return ;
}
return;
});
});


最终的结果也是失败。

浏览器工具栏的刷新按钮属于浏览器自己的内容,目前无法被页面的JS代码所处理,这样就使为什么在点击TAB标签关闭窗口时找不到clientX等属性的原因。JS代码能处理的事件目前只限于document文档。

综上,我们无法再前端区分用户的刷新还是关闭了浏览器。但我们还是有方法完成我们的目标,毕竟有实际的解决方案在用。那就是需要借助session超时来处理,但这无法做到非常实时,但可以将超时时间设置短一些,同时使用空请求一直保持与后台j交互。具体请参看文章:Servlet 中 session 的创建、销毁及监听
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: