Vue 3 中响应拦截器实现后台静默刷新 Token 的关键是提前预判过期、并发控制与请求队列重放:请求前解析 Access Token 的 exp 字段,剩余不足60秒即触发不阻塞的刷新流程,用 Promise 缓存防重复,401 时兜底重放请求,并将 Refresh Token 存于 HttpOnly Cookie 中保障安全。

Vue 3 中响应拦截器实现后台静默刷新 Token,核心不是等 401 才行动,而是提前预判 + 并发控制 + 请求队列重放。真正“无感”的关键,在于避免用户看到登录页、不中断操作、不重复刷新。
提前检查 Token 是否即将过期
不要等到后端返回 401 再处理——那时请求已失败,体验已中断。应在每次请求发出前,就用 jwt-decode 解析本地 Access Token 的 exp 字段,结合当前时间判断是否剩余不足 60 秒(可配置):
- 若即将过期,立即触发刷新流程,但不阻塞当前请求
- 原请求暂存,等待新 Token 到位后自动重发
- 刷新请求本身走独立路径(如不带 Authorization 头),避免被拦截器二次拦截
用 Promise 缓存 + 请求队列防重复刷新
多个请求几乎同时发现 Token 将过期时,必须确保只发起一次刷新请求。常用做法是用一个全局 Promise 变量缓存刷新任务:
{"answer":"OpenClaw Agent 优化套件,防止令牌泄露与上下文膨胀。适用于需实现后台任务隔离或重置与摘要工作流(RAG)的场景。"}
- 首次检测到需刷新 → 调用
refreshToken(),将返回的 Promise 存入变量(如refreshPromise) - 后续请求检测到
refreshPromise正在进行 → 直接await refreshPromise,复用同一结果 - 刷新成功后清空该变量;失败则重置,避免卡死
响应拦截器中接管 401 并重放原始请求
尽管做了提前检查,仍可能因网络延迟、时钟偏差或并发竞争导致某次请求携带了已过期 Token 并收到 401。此时响应拦截器要兜底:
立即学习“前端免费学习笔记(深入)”;
- 判断
error.response.status === 401且!originalRequest._retry - 标记
originalRequest._retry = true,防止循环重试 - 调用刷新逻辑(复用上面的缓存 Promise)
- 拿到新 Token 后,更新请求头:
originalRequest.headers.Authorization = 'Bearer ' + newToken - 用 axios 重新发起
originalRequest,并返回其 Promise,让业务层无感知
Refresh Token 安全存储与失效兜底
Refresh Token 不应存在 localStorage(易被 XSS 窃取),推荐 HttpOnly Cookie 方式由后端下发。前端只需在刷新接口调用时让浏览器自动携带即可:
- 刷新接口(如
/api/refresh-token)必须允许凭 Cookie 验证身份,不依赖前端传参 - 若刷新失败且响应为 403,说明 Refresh Token 也已过期或被撤销 → 清除所有凭证,跳转登录页
- 清除动作包括:localStorage / sessionStorage 中的 token、Pinia 持久化 store 数据、路由守卫状态

















