浏览器关闭实现登出(后端清token)

实现浏览器关闭后,后端记录用户登出日志的最佳方式是通过前端发送请求来通知后端进行记录。以下是一种常见的实现方式,重点就是如何区分用户行为是页面刷新还是关闭浏览器。

js 复制代码
// 写在APP.vue
mounted() {  
    window.addEventListener("beforeunload", () => this.beforeunloadHandler())
    window.addEventListener("unload", () => this.unloadHandler())  
},
  
destroyed() {
    window.removeEventListener("beforeunload", () => this.beforeunloadHandler())
    window.removeEventListener("unload", () => this.unloadHandler())
    clearInterval(this.timer)
},

methods:{
     beforeunloadHandler() {
      this.beforeUnloadTime = new Date().getTime()
    },
    unloadHandler() {
      this.gapTime = new Date().getTime() - this.beforeUnloadTime
      if (this.gapTime <= 5) { //判断是窗口关闭还是刷新,小于5代表关闭,否则就是刷新。
        // 这里是关闭浏览器
        logout()
      }
    },
}

但是经测试,发现上面这种浏览器关闭事件并不是一种可靠的方式来捕捉用户的登出操作,后端并非百分百接收到logout请求,经查资料得知,在unload阶段发送的异步请求是不可靠的,有可能被cancel。后面又尝试了fetch,设置了keepalive(即使浏览器关闭,请求照样发送), 但是又发现gapTime<=5的判断条件也存在兼容性问题,不同浏览器的时间差存在差异。此外还存在一些特殊情况:用户可能直接关闭浏览器窗口、断开网络连接或发生其他异常情况,导致浏览器关闭事件无法被触发,因此pass掉上述方案。

后面也尝试了心跳机制(websocket),也存在局限性,pass。

最后想到了一种最简单,最朴实的方式: 开启定时器每秒往localStorage写入当前时间lastRecordTime(new Date().getTime()), 在请求拦截器中给每个接口请求头带上两个时间,最后一次写入时间lastRecordTime和当前时间nowTime, 后端只要把两个时间相减, 超过5s(自定义)就算登出,清掉redis里相应的token。

js 复制代码
// 写在APP.vue
created (){
    // 每秒写入一次时间
    this.timer = setInterval(() => {
    // 这个判断代表登录成功后才开始写入时间
      if(localStorage.getItem('token')) {
        localStorage.setItem('lastRecordTime', new Date().getTime())
      }
    }, 1000)
  }

另外需要注意, 在登录成功的地方要立即写入一次时间, 不然有BUG。

js 复制代码
  // 写在请求拦截器
  const headers = config.headers;
  /** 用于判断用户是否关闭过浏览器,如果关闭则跳转至登录页面,以及及时清理redis中的token */
  if (localStorage.getItem('lastRecordTime')) {
    headers.lastRecordTime = localStorage.getItem('lastRecordTime');
  }
  headers.nowTime = new Date().getTime();

总结一下,目前没发现哪种方式可以提供一种可靠的通信方式去通知后端清除token, 通过两个时间差的方式相对靠谱。

相关推荐
软件技术NINI几秒前
前端怎么学
前端
O***p6042 分钟前
前端体验的下一次革命:从页面导航到“流式体验”的系统化重构
前端·重构
一岁天才饺子6 分钟前
XSS挑战赛实战演练
前端·网络安全·xss
Hilaku8 分钟前
Canvas 粒子特效:带你写一个黑客帝国同款的代码雨(附源码)😆
前端·javascript·前端框架
文心快码BaiduComate15 分钟前
我用文心快码Spec 模式搓了个“pre作弊器”,妈妈再也不用担心我开会忘词了(附源码)
前端·后端·程序员
JH灰色19 分钟前
【大模型】-LangChain--stream流式同步异步
服务器·前端·langchain
lxh011334 分钟前
二叉树中的最大路径和
前端·算法·js
CC码码1 小时前
前端字符串排序搜索可以更加细化了
前端·javascript·面试
喵爱吃鱼1 小时前
kuma-ui中Flex vs FlexMin的关键区别
前端
codingMan1 小时前
[Android Compose] 拒绝闪烁!打造丝滑的聊天页面列表(仿微信效果)
前端