如何监听浏览器中同一域名的 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
            });
            }
        };

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

5089 次点击
所在节点    JavaScript
41 条回复
encro
2022-08-18 10:27:48 +08:00
session 不设置过期时间,默认行为就是这样。
encro
2022-08-18 10:29:23 +08:00
这是后端的坑需要前端填吗?

打脸:

如果客户端异常了,停电了,服务端就不会自动退出吗?
maggch97
2022-08-18 10:39:18 +08:00
localStorage 周期性写时间。下次打开的时候判断时间是不是过期了,过期就 logout
zjsxwc
2022-08-18 10:47:20 +08:00
“完全关闭浏览器后退出”
不就是没设置到期时间的 session 默认行为吗
runze
2022-08-18 11:15:39 +08:00
典型的 XY 问题,楼主还是先说一下原本的目的是什么比较好。

https://noob.tw/xy-problem/
Belmode
2022-08-18 11:15:48 +08:00
思路错了。浏览器做不到你这需求中的效果,即使有也必定很绕。让服务端来做。
vanton
2022-08-18 11:37:30 +08:00
让后端去做,前端没这个义务做。
wunonglin
2022-08-18 11:41:04 +08:00
起 ws 啊,ws 断了服务器就把 session 删了不就好了
lisongeee
2022-08-18 11:47:02 +08:00
你这个代码根本不管用啊,sessionStorage 各个标签页是完全独立的
测试如下代码
```js
sessionStorage.setItem('reloaded', 'yes');
window.onunload = function(e) {
if (sessionStorage.getItem('reloaded') == null) {
fetch("http://127.0.0.1:8080/on", {
method: "GET",
keepalive: true
});
} else {
fetch("http://127.0.0.1:8080/off", {
method: "GET",
keepalive: true
});
}
};
```
只打开一个标签页然后关闭,结果如下
![img]( https://github.com/lisonge/src/raw/main/img/Snipaste_2022-08-18_11-43-07.png)
lisongeee
2022-08-18 11:53:19 +08:00
一个可能可行的解法是 Service Worker ,它独立于 标签页 存在,你可以在每个标签页 onunload 的时候给 Service Worker postMessage ,然后 Service Worker 去调用 await clients.matchAll() ,如果得到的列表长度是 0 ,就 doYourWork
有一个问题,文档里没有说明 Service Worker 何时被停止,而且我懒得测试,你可以自己试试
yolee599
2022-08-18 13:04:19 +08:00
如果用户端直接杀浏览器进程或者浏览器崩了,就永远不退出吗?
viakiba
2022-08-18 14:21:48 +08:00
量不大心跳就完事了
nothingistrue
2022-08-18 15:02:54 +08:00
那些让后端处理的,你们是哪里学的开发,浏览器的事件有没有触发,服务器端要拿头去判断吗。现行 HTTP 规范下,只有标签页关闭和窗口关闭两个事件,没有特定标签页全部关闭事件,这事拿常规手段做不了。

我想到一个思路,需要前后端配合。前端,每个页面定时上报自己还活着,可以用 websocket 加心跳,也可以就是单纯的 JavaScript 定时器(如果标签页是频繁打开关闭的,那就千万别用 websocket ,DDOS 了)。后端需要监控当前 Session (如果能定位到客户端也可以把维度换成客户端)的“活着的页面数”,变成零的时候就触发登出操作。

但是,跟产品沟通一下,把需求变成“5 分钟或者半小时内没操作就自动登出”,回是更好的选择。
lambdaq
2022-08-18 15:04:29 +08:00
@lisongeee 然后用户来了个 chrome 和 firefox 双开
nothingistrue
2022-08-18 15:06:06 +08:00
不嫌 LOW ,不怕性能爆炸,并且还不关心是否长时间没操作的话,把会话超时时间定为 1 分钟,然后每个页面都弄个 30 秒的定时器触发垃圾请求,也能大力出奇迹。
explore365
2022-08-18 15:08:53 +08:00
cookie 定时更新每个 tab 时间戳,检查 tab 列表,时间戳超时则为退出。
Puteulanus
2022-08-18 15:10:56 +08:00
换一个思路,用跨标签页通信呢?

第一个标签页触发登陆之后,登陆凭据不是保存在 cookie 里,而是只存在内存里,从第二个标签页开始,打开时的登陆凭据都靠和已经打开的标签页沟通来拿到

这样所有标签页关闭之后合法登陆凭据消失,下一个“第一个标签页”拿不到凭据,再次触发用户登陆操作
nothingistrue
2022-08-18 15:31:28 +08:00
刚去看了下 localStorage 、sessionStorage ,发现 sessionStorage 是基于标签页的,这样是有办法监控当前域名打开的标签页的个数的。

思路就是:
用与标签页无关的 localStorage 存储计数,每打开一个标签页就加 1 ,每关闭一个标签页就减 1 ;
用于标签页有关的 sessionStrrage 结合 load unload 事件来触发标签页打开和标签页关闭事件,主要是把刷新标签页给区分出去,怎么区分还要仔细想一想,不是太好处理。
给 unload 事件加个监听,通过 localStorage 的计数,来判断是否需要触发登出处理,也需要区分刷新跟关闭。
lonenol
2022-08-18 15:35:13 +08:00
需求不合理,直接砍需求。。
dudubaba
2022-08-18 15:38:16 +08:00
试试 BroadcastChannel 监听

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

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

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

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

© 2021 V2EX