Axios中捕获401错误刷新Token并重试请求的问题
Axios 401拦截后刷新Token并重发请求的问题解决
问题描述
需求是在Axios中捕获401错误,刷新API Token后用新的access_token重新发起请求并获取响应,但当前实现里,拦截器的重发逻辑会在原始请求的catch处理函数之后触发,导致原始请求拿不到重发后的响应。
问题原因
当前拦截器处理401时,内部的token刷新、重发请求都是异步操作,但拦截器直接返回了Promise.reject(error),没等异步操作完成就结束了。同时,内部axios.request(refreshConfig)的then链里返回的重发请求Promise,没有传递到拦截器的外部Promise链中,导致原始请求的Promise提前进入reject状态,先触发了catch回调。
修复后的代码
修正后的Axios响应拦截器
axios.interceptors.response.use( response => response, error => { const status = error.response ? error.response.status : null; if (status === 401) { // 用Promise包装整个异步逻辑,让拦截器返回这个Promise,等待异步操作完成 return new Promise((resolve, reject) => { const refreshConfig = { method: 'post', maxBodyLength: Infinity, url: 'https://accounts.spotify.com/api/token', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + (new Buffer.from(this.clientId + ':' + this.clientSecret).toString('base64')) }, data: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: this.user.spotify_refresh_token, client_id: this.clientId }), }; axios.request(refreshConfig) .then((refreshResponse) => { this.user.spotify_access_token = refreshResponse.data.access_token; // 等待用户数据保存完成后再重发请求 this.user.save() .then(() => { console.log('Access token refreshed'); // 更新原请求的Authorization头 error.config.headers['Authorization'] = 'Bearer ' + refreshResponse.data.access_token; console.log('Retrying request'); // 重发请求,将结果resolve给原始请求的then回调 resolve(axios(error.config)); }) .catch(saveError => { reject(saveError); }); }) .catch(refreshError => { reject(refreshError); }); }); } // 非401错误直接reject return Promise.reject(error); } );
原始请求函数无需修改,现在可正确获取重发后的响应
getCurrentPlaying = async () => { let config = { method: 'get', maxBodyLength: Infinity, url: 'https://api.spotify.com/v1/me/player/currently-playing', headers: { 'Authorization': `Bearer ${this.user.spotify_access_token}` } } axios.request(config) .then((response) => { console.log(JSON.stringify(response.data)) }) .catch((error) => { // 仅当刷新token或重发请求失败时才触发这里 console.log('getCurrentPlaying', error.response?.data || error.message) }) }
关键修改点
- 将401处理的异步逻辑(刷新token、保存用户、重发请求)包装在新的
Promise中,拦截器返回这个Promise,让原始请求的Promise等待异步操作完成。 - 用
resolve(axios(error.config))把重发请求的结果传递给原始请求的then回调,而非在内部then里直接return。 - 统一处理各个环节的错误,用
reject把错误传递到原始请求的catch回调。
内容的提问来源于stack exchange,提问作者OliverKhl
相关产品推荐
相关产品推荐

