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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:50:20