推荐使用 pinia 管理 token:将 accesstoken 和 refreshtoken 定义为 ref 并同步 localstorage;响应拦截器捕获 401 后调用 store 刷新逻辑,通过 isrefreshing 与 pendingrequests 队列防并发;刷新成功后重发请求并更新 token。

Token 存储与状态响应式设计
在 Vue 3 中,推荐使用 Pinia 替代 Vuex 进行全局状态管理。需将 access token 和 refresh token 同时纳入 store 的响应式字段中,而非仅存于 localStorage 或 sessionStorage —— 否则无法触发组件自动更新或拦截器中的 reactive 重试逻辑。
关键点:
- 定义两个 ref 状态:`accessToken` 和 `refreshToken`,初始值从 localStorage 读取(兼顾页面刷新后恢复)
- 暴露 setter 方法(如 `setTokens(accessToken, refreshToken)`),内部同步更新 ref 值 + 持久化到 localStorage
- 避免直接操作 localStorage 后 store 状态不同步,导致后续请求仍用旧 token
响应拦截器中统一捕获 401 并触发刷新
所有业务请求失败且响应状态码为 401 时,不立即 reject,而是交由 store 的刷新逻辑处理。注意必须排除刷新接口自身(通过 config 标识,如 `config.__isRefresh`)——否则会陷入递归刷新。
实现要点:
- 在响应拦截器中判断 `error.response?.status === 401 && !originalRequest.__isRefresh`
- 调用 store 中的 `refreshAccessToken()` 方法(返回 Promise)
- 刷新成功后,用新 token 重写原请求的 Authorization 头,并用 axios.request() 重发
- 刷新失败(如 refresh token 也过期或校验不通过),清空 store 并跳转登录页
防并发刷新与请求队列机制
多个请求几乎同时触发 401 时,若各自发起刷新,会造成多次重复请求、token 覆盖冲突甚至后端拒绝(如 refresh token 一次性失效)。需在 store 层维护一个轻量级协调状态。
标准做法:
- 声明 `isRefreshing = ref(false)` 和 `pendingRequests = ref([])`
- 首次发现 401 时,设 `isRefreshing = true`,并将当前请求的重试函数 push 到队列
- 后续 401 请求暂不执行刷新,只把重试函数入队
- 刷新成功后,遍历队列并依次 resolve;最后清空队列、重置 `isRefreshing`
刷新逻辑与 Token 安全更新
刷新接口本身应是一个独立请求(如 /auth/refresh),携带当前有效的 refresh token。后端验证通过后,返回新的 access token(可能含新 refresh token)。
前端处理细节:
- 刷新成功响应中,优先提取新 access token;若后端也轮换了 refresh token,一并更新
- 调用 `setTokens(newAccess, newRefresh)`,确保 store 和本地存储同步
- 新 access token 需立即生效于后续所有请求,因此拦截器中获取 token 必须读取 store 的 ref 值,而非缓存副本
- 建议后端对 refresh token 做单次使用或滑动窗口校验,防止重放攻击
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











