Vue.js中如何使用Axios拦截器无需刷新页面无感刷新AccessToken
问题修复方案
核心问题原因
你的代码只完成了刷新token的请求逻辑,缺少两个关键步骤导致需要手动刷新页面生效:
- 仅修改了当前失败请求的请求头,没有更新axios全局默认请求头,后续新发起的请求仍然会携带旧token
- 拿到新token后没有重新发起之前失败的请求,也没有正确返回promise链,拦截器没有等待刷新逻辑执行完成就终止了流程
修复后代码
// 可选:添加一个刷新锁,避免并发请求时重复发起refresh请求 let isRefreshing = false // 存储并发请求的重试队列 let requestQueue = [] axios.interceptors.response.use(undefined, function(error) { if (!error) return Promise.reject(error) const originalRequest = error.config; // 401且不是重试请求 if (error.response.status === 401 && !originalRequest._retry) { if (isRefreshing) { // 正在刷新token的话,把当前请求加入队列等待 return new Promise(resolve => { requestQueue.push(token => { originalRequest.headers["Authorization"] = `Bearer ${token}` resolve(axios(originalRequest)) }) }) } originalRequest._retry = true; isRefreshing = true // 发起刷新token请求 return axios.post("auth/refresh", { refreshToken: store.state.refreshToken }).then(res => { const newToken = res.data.token const newRefreshToken = res.data.refreshToken // 1. 更新store存储 store.dispatch('setToken', newToken) store.dispatch('setRefToken', newRefreshToken) // 2. 更新axios全局默认请求头,后续新请求自动携带新token axios.defaults.headers.common["Authorization"] = `Bearer ${newToken}` // 3. 执行队列中所有等待的请求 requestQueue.forEach(cb => cb(newToken)) requestQueue = [] // 4. 重新发起本次失败的请求,返回请求结果 originalRequest.headers["Authorization"] = `Bearer ${newToken}` return axios(originalRequest) }).catch(refreshError => { // 刷新token失败兜底:清除本地存储的无效token,跳转登录页 store.dispatch('clearToken') store.dispatch('clearRefToken') window.location.href = '/login' return Promise.reject(refreshError) }).finally(() => { isRefreshing = false }) } return Promise.reject(error); })
关键改动说明
- 新增axios全局请求头更新逻辑,后续所有新发起的请求都会自动携带新的token,不需要刷新页面
- 刷新token成功后重新发起原本失败的请求,用户侧完全无感知,不会出现操作中断的情况
- 新增刷新锁和请求队列,解决同时多个请求返回401时重复发起refresh请求的问题
- 新增refresh请求失败的兜底逻辑,避免refresh token也过期时页面无响应
内容的提问来源于stack exchange,提问作者Ogurinka Benjamin
相关产品推荐
相关产品推荐

