如何监听浏览器中同一域名的 tab 全部关闭?

2022-08-18 10:26:22 +08:00
 Jexxie

奇葩需求:所有这个网站的标签页 tab 全部关闭则退出登陆(调用 logout 接口)。

(以下代码是目前的实现,完全关闭浏览器后退出登陆)

 // 刷新和关闭网页都会触发 onunload, 因此用 sessionStorage 区分,浏览器完全关闭后会清空 sessionStorage
        sessionStorage.setItem('reloaded', 'yes');
        window.onunload = function(e) {
            if (sessionStorage.getItem('reloaded') == null) {
                fetch("/logout", {
                method: "POST",
                // keepalive 属性用于页面卸载时,告诉浏览器在后台保持连接,继续发送数据。开启了 keepalive 属性后,网页就算被关闭了,请求被会继续执行而不会中断。
                keepalive: true
            });
            }
        };

请问,有没有方法实现检测到所有同域标签页关闭的方法?

5564 次点击
所在节点    JavaScript
41 条回复
nothingistrue
2022-08-18 15:40:08 +08:00
还是遇到难题了,新建标签页跟刷新事件很好区分,但是关闭标签页跟刷新事件,不好区分。
yunye
2022-08-18 15:50:03 +08:00
谁提的需求谁自己来实现
shyling
2022-08-18 16:00:52 +08:00
一个标签连个 ws ,全断了就全关了
nothingistrue
2022-08-18 16:05:01 +08:00
我搜了一圈,没有找到区分 unload 是刷新还是关闭的方法,也就是说没有标签页关闭事件( windows.onclose 还在试验中)。所以这个每必要再研究下去了,就是不可实现的需求,怼回去。就留一个长时间未操作服务器端自动退出就可以了,浏览器端就别搞骚套路了。
Imindzzz
2022-08-18 16:49:41 +08:00
window.onload = () => {
const count = parseInt(localStorage.getItem('count') || '0', 10);
localStorage.setItem('count', count + 1 + '');

const lastExitTime = parseInt(sessionStorage.getItem('lastExitTime') || '0', 10);
// 三秒内回来,表示是刷新了
if (lastExitTime && Date.now() - lastExitTime < 30000) {
// TODO 发送接口 还原登录状态
}
};

window.onbeforeunload = (event) => {
const count = parseInt(localStorage.getItem('count') || '0', 10);
localStorage.setItem('count', count - 1 + '');
if (count <= 1) {
// TODO 但是其实这里无法区分是刷新还是关闭。 需要后端
sessionStorage.setItem('lastExitTime', Date.now().toString());

// TODO 发送接口退出
// 发送网络请求建议使用 sendBeacon https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/sendBeacon

// 注意:页面必须有用户操作才能正常拦截
event.preventDefault();
event.returnValue = '所有都关闭了';
return '所有都关闭了';
}
};
autoxbc
2022-08-18 16:50:37 +08:00
用 BroadcastChannel 向其他标签广播,没有回应说明是最后一个标签,然后用 sendBeacon 向服务器发送信息
lin07hui
2022-08-18 17:08:16 +08:00
当前的浏览器都没法区分开“关闭标签页跟刷新事件”
dtdths1
2022-08-18 19:16:00 +08:00
无法监听,over 。你要是想退出可用心跳,让服务端判断
v2eb
2022-08-18 19:27:16 +08:00
每个 tab 页分配个唯一 id , 集合形式存到 local storage .tab 页关闭时判断集合长度
chnwillliu
2022-08-18 19:47:32 +08:00
@v2eb 关闭和刷新分不出来的,只有一个 tab 一刷新结果登出了?
chnwillliu
2022-08-18 19:55:24 +08:00
不妨想想为什么登出一定要调用 logout 接口,不调用会有什么后果?是后端有资源要释放么?用户浏览器直接崩也是可能没机会调用 js 的 unload 的,所以关键逻辑不能依赖 logout 接口。
zhuweiyou
2022-08-18 21:29:01 +08:00
session 行为就是这样的. 不需要前端干预. 这帮后端不行,还要前端背锅?
realpg
2022-08-18 21:52:38 +08:00
这需求有啥奇葩的...
这不是动态网页出来这二三十年的最基本的一个操作^
chnwillliu
2022-08-19 08:13:36 +08:00
@realpg 这还不奇葩?这跟动态网页有什么关系?你哪怕是 windows 客户端也不能保证用户退出就一定能调用到服务端的 logout 接口。我强杀进程,直接强制关机等等,都可能导致客户端直接就消失不调用你的 logout 接口。

logout 是要干什么?统计在线人数么?还是释放啥资源还是什么?非要强依赖客户端在线与否,那只能建立 socket 或者让客服端发心跳。期望客户端恭恭敬敬给你调用 logout ,那只能说无法保证。
realpg
2022-08-19 12:01:40 +08:00
@chnwillliu #34
现在的开发者连有个东西叫 session,有个东西叫 cookie 都不知道了
realpg
2022-08-19 12:11:00 +08:00
@chnwillliu #34
而且, 不依赖 cookie, 也可以用 localstorage 和 sessionstorage 实现他要求的掉登录状态机制
DingJZ
2022-08-19 13:42:09 +08:00
这玩意还真实现了一个,上面大家说 cookie 之类的,是可以,但是后端不改怎么办,整个用户体系都是基于 token 的,改不现实,需求还是提给前端的。
用 BroadcastChannel ,可以 tab 之前通信,退出的时候发通知,所有页面订阅,我把代码放在 nginx 里注入到项目里,这样业务不需要关注
dtdths1
2022-08-19 16:39:51 +08:00
凡是让客户端主动去调的,不管用什么,全不靠谱。各种异常情况、兼容问题,不要想当然
chnwillliu
2022-08-20 14:44:01 +08:00
@realpg 依赖 session 类型的 cookie 然后捏?怎么在合适的时候调用 logout 接口?所以说要改实现,因为没法保证调用后端的 logout 接口。

还有哦,sessionStorage 和 session 类型的 cookie 行为不一致。sessionStorage 不跨 tab.
chnwillliu
2022-08-20 14:48:59 +08:00
@realpg 对,其实用 session 类型的 cookie 存东西就行,用户关了所有 tab 自动被清掉。用 sessionStorage 存的话要考虑跨 tab 共享问题,解决完这个问题,行为就和 session cookie 一致了。

利用好了,根本就不要什么 logout 接口。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/873662

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX