vue中axios自动续期token需结合响应拦截器、请求重试与状态标记:响应拦截器提取x-access-token/x-refresh-token;用_retry标记和promise队列避免重复刷新;请求拦截器实时读取pinia/vuex中最新token;刷新请求须使用独立无认证的axios实例。

Vue 项目中用 Axios 处理响应头里自定义 Token(比如 X-Access-Token、X-Refresh-Token)的自动续期,关键不在“怎么取响应头”,而在于“怎么让后续请求自动带上新 Token + 避免重复刷新 + 保证请求不丢失”。核心是结合响应拦截器 + 请求重试机制 + 状态标记,而不是靠手动解析每次响应头再塞回去。
响应头中提取自定义 Token 的正确方式
后端若把新 Token 放在响应头(如 X-Access-Token),前端必须在响应拦截器里显式读取,不能依赖 Authorization 字段自动携带:
- 用
response.headers['x-access-token'](注意大小写不敏感,但建议统一小写访问)获取新 access_token - 同理用
response.headers['x-refresh-token']获取新 refresh_token(如有轮换) - 务必检查 header 是否存在且非空,避免 undefined 导致后续报错
- 不要覆盖 localStorage/sessionStorage 中的旧 token 直到刷新成功——防止中间态失效
用 _retry 标记+队列暂存解决并发请求冲突
当多个请求几乎同时收到 401,只应发起一次刷新请求,其余请求等待结果并重放。否则会触发多次刷新、Token 被覆盖、甚至被后端拒绝(refresh_token 一次性使用):
- 给原始请求 config 添加唯一标记:
originalRequest._retry = true - 维护一个待重试请求队列(数组或 Promise 队列),在刷新成功后统一 resolve
- 刷新失败时,清空队列并全局登出,避免脏状态累积
- 不要用 setTimeout 模拟“等待”,要用 Promise 链式 await 实现真等待
请求拦截器要动态读取最新 Token
刷新完成后,token 已更新,但已发出的请求(包括重试请求)必须带上新值。这就要求请求拦截器不是“静态读取”,而是每次发请求时实时取:
- 把 token 存在 pinia 或 vuex 的可响应式 store 中(如
authStore.accessToken) - 请求拦截器里直接读取该响应式字段,而非从 localStorage 读——确保拿到的是刚刷新后的最新值
- 如果用 localStorage,需配合 storage 事件监听跨 tab 同步,但不如响应式 store 可靠
- 重试请求发出前,确保 store 已更新,再设置
config.headers['X-Access-Token']
刷新接口调用要独立于主实例
刷新 token 的请求本身不能走带 token 的 axios 实例(否则会无限递归 401),也不能受同一套拦截器影响:
- 新建一个无认证头的 axios 实例(如
refreshApi),专用于调用/auth/refresh - 该实例不挂载请求/响应拦截器,或至少禁用 401 处理逻辑
- 刷新请求应携带 refresh_token —— 通常放在 header(
X-Refresh-Token)或 request body,按后端约定来 - 刷新失败(如 401 或 403)说明 refresh_token 也失效,此时应清除所有凭证并跳转登录页
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










