浏览器关闭实现登出(后端清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, 通过两个时间差的方式相对靠谱。

相关推荐
灵感__idea7 小时前
Hello 算法:贪心的世界
前端·javascript·算法
GreenTea8 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd10 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌10 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈10 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫10 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝10 小时前
svg图片
前端·css·学习·html·css3
王夏奇11 小时前
python中的__all__ 具体用法
java·前端·python
大家的林语冰11 小时前
《前端周刊》尤大开源 Vite+ 全家桶,前端工业革命启动;尤大爆料 Void 云服务新产品,Vite 进军全栈开发;ECMA 源码映射规范......
前端·javascript·vue.js
jiayong2312 小时前
第 8 课:开始引入组合式函数
前端·javascript·学习