小问题背后的思考:Token如何跨页签同步

问题

昨天组员遇到了一个非常有意思的token问题,在群里寻找答案,过程是这样的。 在浏览器打开两个页签A和B,分别登录A系统,此时两个页签属于同域名、同会话状态。 前端的token是保存在storage中的,同时在vuex的store中也保存了一份。

此时打开B页签的页面,退出又重新登录系统,storage里面的token会重新生成,由于B页签是重新登录的,所以,B页签的页面是可以正常加载成功的。

此时问题出现了,A页签的系统在文件上传时报错,提示token失效,因为上传的token是通过vuex的store进行获取的,B页签虽然重新登录了系统,但是A页签的store数据并没有刷新,如何在不刷新A页签的情况下,及时更新Token状态?

如何解决

大家可以思考一下,这个问题都有哪些解决办法。

监听 Storage 变化

给window添加storage事件,当localStorage或者sessionStorage值发生变化时执行。

js 复制代码
onMounted(() => {
  window.addEventListener("storage", function (event) {
    console.log(
      "Storage change: ",
      event.key,
      "from",
      event.oldValue,
      "to",
      event.newValue
    );
  });
});

动画演示:

开启两个页签,分别打开同一个页面,右侧点击登录时,会给localStorage写入一个token,此时左侧页面监听到了数据变化。

如果是真实业务场景,我们就可以根据登录token更新vuex中的状态,从而避免老页面过期问题。

进一步扩展

假设,右边的登录和退车操作后,左边保持同步,如何实现?

js 复制代码
<script setup>
import { ref, onMounted } from "vue";

const userName = ref("");
onMounted(() => {
  localStorage.removeItem("token");
  window.addEventListener("storage", function (event) {
    console.log(
      "Storage change: ",
      event.key,
      "from",
      event.oldValue,
      "to",
      event.newValue
    );
    if (event.key === "token" && event.newValue) {
      userName.value = "河畔一角";
    } else {
      userName.value = "";
    }
  });
});
// 登录
const login = () => {
  userName.value = "河畔一角";
  localStorage.setItem("token", "999");
};
// 退出
const logout = () => {
  userName.value = "";
  localStorage.removeItem("token");
};
</script>

我们在监听事件里面,根据token值来判断用户状态,从而保持同步。

动画演示:

增加登录和退出按钮,定义userName变量,登录后,给userName赋值,并向localStorage中写入token,退出后,清空值。

监听事件里面可以根据token的变化,控制userName的值,从而实现左右页面同步。

注意: 大家通过动画演示应该发现了一个问题,为什么右侧页面的控制台没有打印值?是因为原始页面作为触发源,不参与事件监听,通过这个机制可以实现多个页面之间的通信。

使用 BroadcastChannel

BroadcastChannel 允许在相同的源在浏览器上下文(windows,tabs,frames或者iframes)之间进行简单的通信。

它有几个知识点:

  • 创建频道:new BroadcastChannel('channel')
  • 发送消息:channel.postMessage(message);
  • 接收消息:channel.onmessage = (data)=>{}
  • 异常处理:channel.onmessageerror = (e)=>{}
  • 关闭频道:channel.close()

代码示例:

js 复制代码
<script setup>
import { ref, onMounted } from "vue";
const channel = new BroadcastChannel("myChannel");
const userName = ref("");
onMounted(() => {
  channel.onmessage = function (event) {
    console.log("Received message:", event.data);
    if (event.data === "token is null") {
      userName.value = "";
    }else{
      userName.value = "河畔一角";
    }
  };
});
// 登录
const login = () => {
  channel.postMessage("token is 999");
  userName.value = "河畔一角";
};
// 退出
const logout = () => {
  channel.postMessage("token is null");
  userName.value = "";
};
</script>

动画演示:

这个方案,其实就不需要去监听storage的变化了,因为在退出的时候,可以直接发布一条消息,接收到消息以后,就可以更新页面状态了。

其他

  • web worker主要用来做计算的,不能直接用于跨标签通信,不太适合。
  • window.postMessage主要用来实现跨页面通信,比如 A页面通过postMessage给B页面发送消息,此场景也不太适合。
  • websocket 固然可以实现,但用在这个场景岂不浪费。
  • 轮询:虽然也能勉强实现,但一般用在异步回调场景,此处也不适合。

总结

其实对于token更新,本身一个非常小的问题,甚至都可以忽略,如果出现了,手动刷新一下页面即可。但从解决问题的角度出发,它的确是一个问题,那就需要考虑跨页签通信。

上面的两套方案,我反而觉得监听storage是最简单的。如果你有更好的方案,可以贴在评论区,共同探讨。

感谢大家,我是河畔一角,一名普通的前端工程师。

相关推荐
徐小夕1 分钟前
下载量超 30 万的开源智能体 Prime Agent:它把自己从 TypeScript 重写成了 Rust
前端·vue.js·github
Zhao-Jichao6 分钟前
AI Prompting for Everyone 课程笔记 - P20 实验与期末项目 Lab and Final Project
前端·人工智能·笔记
挖掘狂人24 分钟前
AI PC 分水岭:2026 过半 PC 搭载本地 AI,端云协同才是核心
人工智能·程序员·ai编程
Moment31 分钟前
为什么这么多 Agent Harness 都选择 TypeScript
前端·后端·面试
toooooop838 分钟前
CRMEB 故障排查笔记:安全网关只放行 GET/POST 怎么办
前端·javascript·vue.js·thinkphp6·crmeb
软件技术NINI1 小时前
基于SpringBoot和Vue的项目评审系统
javascript·vue.js·spring boot·后端·spring·毕业设计·毕设
涛涛ing1 小时前
我现在最怕的不是 AI 写不出代码,是它写得太快,快到我不好意思说“等一下”
前端
AllData公司负责人1 小时前
【产品便捷使用一】AIIData 数据中台:企业基础版核心能力支持,一站式全链路数据处理实操指南
大数据·前端·数据治理·数据可视化·数据开发·数据服务·数据接入
vipxieliang1 小时前
JavaScript 模板字符串与标签模板:不只是拼接
前端·javascript
恋猫de小郭1 小时前
Flutter 开始支持 Jetpack Compose Platform View
android·前端·flutter