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

Axios拦截器中Async/Await未等待请求完成就执行的问题排查

问题根因

核心问题出在fetchAuthToken的Promise链断裂,加上并发场景的状态标记逻辑有缺陷:

  • 直接导致执行顺序错乱的原因:你在/csrf-cookie请求的.then回调里调用apiClient.get("/token")时,没有return这个Promise实例。外层返回的Promise链会在CSRF请求完成后直接进入resolve状态,不会等待后续的/token请求执行完成,所以await fetchAuthToken()会提前返回,先打印then this,等token请求跑完才打印this,和预期顺序完全相反。
  • 隐藏的并发问题:你用isFetchingToken布尔值标记取token的状态,当页面同时发起多个业务请求时,第一个请求触发取token逻辑后,后续请求判断到isFetchingToken为true会直接返回false,不会等待token获取完成,最终会把false作为token塞到请求头里,导致鉴权失败。
  • 其他逻辑隐患:空的.catch会静默吞掉鉴权请求的报错,拦截器的错误回调没有returnPromise.reject(error),会吞掉请求错误,很难排查问题;直接给config.headers赋值会覆盖请求原本携带的其他自定义请求头。
修复方案

首先调整全局变量定义,用Promise缓存替代布尔标记,解决并发等待问题:

let authToken = checkLocalStorage("token", false);
// 存储正在进行的取token请求Promise,替代原有的isFetchingToken标记
let authTokenPromise = null;

重写fetchAuthToken,保证Promise链完整,同时处理并发和错误逻辑:

function fetchAuthToken() {
  // 本地已有token直接返回
  authToken = checkLocalStorage("token", false);
  if (authToken) return Promise.resolve(authToken);
  // 已有正在进行的取token请求,直接返回该Promise,避免重复请求
  if (authTokenPromise) return authTokenPromise;

  authTokenPromise = apiClient
    .get("/csrf-cookie")
    .then(() => {
      // 必须return这个请求Promise,保证外层链等待token请求完成
      return apiClient.get("/token");
    })
    .then((res) => {
      authToken = res.data.bearer_token;
      localStorage.setItem("token", JSON.stringify(authToken));
      console.log("this");
      return authToken;
    })
    .catch((err) => {
      // 请求失败清空缓存,支持后续重试
      authTokenPromise = null;
      // 抛出错误,不要静默吞错
      throw err;
    });

  return authTokenPromise;
}

调整Axios请求拦截器逻辑,补全错误处理和请求头合并:

apiClient.interceptors.request.use(
  async (config) => {
    // 鉴权接口直接放行,不进入鉴权逻辑
    if (config.url.includes("/csrf-cookie") || config.url.includes("/token")) {
      return config;
    }

    if (!authToken) {
      authToken = await fetchAuthToken();
      console.log("then this");
    }

    // 合并原有请求头,避免覆盖其他自定义头
    config.headers = {
      ...config.headers,
      Authorization: `Bearer ${authToken}`,
    };
    return config;
  },
  (error) => {
    // 必须return rejected Promise,否则错误会被吞
    return Promise.reject(error);
  }
);

修复后执行顺序会完全符合预期:先打印this(token请求完成),再打印then this(await结束继续执行业务请求逻辑),同时并发场景下也不会出现重复请求、token未就绪就发业务请求的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:54:22