Vue.js中使用Axios拦截器刷新JWT Token后无法重发原请求
解决Vue.js中JWT Token刷新后原请求重发失败的问题
问题分析
你的代码已成功完成Token刷新,但重发原请求失败,核心原因有两点:
- 重发请求时,
error.config中的Authorization头仍为过期的旧Token,未同步更新为新Token - 直接修改
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
相关产品推荐
相关产品推荐

