You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js中使用Axios拦截器刷新JWT Token后无法重发原请求

解决Vue.js中JWT Token刷新后原请求重发失败的问题

问题分析

你的代码已成功完成Token刷新,但重发原请求失败,核心原因有两点:

  1. 重发请求时,error.config中的Authorization头仍为过期的旧Token,未同步更新为新Token
  2. 直接修改store.state.user不符合Vuex状态更新规范,可能导致状态更新不及时

修复步骤

1. 修正Vuex状态更新方式

不要直接修改store.state.user,通过Vuex的mutation来更新状态(假设你的store中定义了SET_USER mutation):

// 替换原有的 store.dispatch("user",user)
const updatedUser = {
  ...store.state.user,
  token: newtokens.data.token,
  refreshtoken: newtokens.data.refreshtoken
}
store.commit('SET_USER', updatedUser)

2. 手动更新重发请求的请求头

仅修改axios.defaults.headers.common不会同步更新已有请求配置的头信息,需要手动更新error.config中的授权头:

// 更新当前请求的授权头
const newAuthHeader = 'Bearer ' + updatedUser.token
error.config.headers['Authorization'] = newAuthHeader
// 同步更新全局默认头
axios.defaults.headers.common['Authorization'] = newAuthHeader
// 重发原请求
return axios(error.config)

3. 可选优化:防止并发请求重复刷新Token

如果多个请求同时返回401,会重复触发Token刷新,可添加锁机制避免重复请求:

// 拦截器外定义锁变量和失败请求队列
let isRefreshing = false
let failedRequests = []

axios.interceptors.response.use(function (response) {
  return response
}, async function (error) {
  if (error.response.status === 401) {
    if (!isRefreshing) {
      isRefreshing = true
      try {
        const newtokens = await axios.post('RefreshToken', {
          oldtoken: store.state.user.token,
          refreshtoken: store.state.user.refreshtoken
        })
        const updatedUser = {
          ...store.state.user,
          token: newtokens.data.token,
          refreshtoken: newtokens.data.refreshtoken
        }
        store.commit('SET_USER', updatedUser)
        const newAuthHeader = 'Bearer ' + updatedUser.token
        axios.defaults.headers.common['Authorization'] = newAuthHeader

        // 重发所有排队的失败请求
        failedRequests.forEach(request => request.onSuccess(newAuthHeader))
        failedRequests = []

        // 重发当前请求
        error.config.headers['Authorization'] = newAuthHeader
        return axios(error.config)
      } catch (refreshError) {
        // 刷新失败,清空用户状态并跳转登录页
        store.commit('CLEAR_USER')
        failedRequests.forEach(request => request.onFailure(refreshError))
        failedRequests = []
        return Promise.reject(refreshError)
      } finally {
        isRefreshing = false
      }
    } else {
      // 当前正在刷新Token,将请求加入队列等待
      return new Promise((resolve, reject) => {
        failedRequests.push({
          onSuccess: (authHeader) => {
            error.config.headers['Authorization'] = authHeader
            resolve(axios(error.config))
          },
          onFailure: (err) => {
            reject(err)
          }
        })
      })
    }
  }
  return Promise.reject(error)
})

修复后的核心代码片段

axios.interceptors.response.use(function (response) {
  return response
}, async function (error) {
  if (error.response.status === 401) {    
    const newtokens = await axios.post('RefreshToken', {
      oldtoken: store.state.user.token,
      refreshtoken: store.state.user.refreshtoken
    })
    // 正确更新用户状态
    const updatedUser = {
      ...store.state.user,
      token: newtokens.data.token,
      refreshtoken: newtokens.data.refreshtoken
    }
    store.commit('SET_USER', updatedUser)
    // 更新全局和当前请求的授权头
    const newAuthHeader = 'Bearer ' + updatedUser.token
    axios.defaults.headers.common['Authorization'] = newAuthHeader
    error.config.headers['Authorization'] = newAuthHeader
    // 重发原请求
    return axios(error.config)
  }
  return Promise.reject(error)
})

内容的提问来源于stack exchange,提问作者Placsx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:20:25