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

Axios拦截器重试401请求时修改POST请求Content-Type问题

问题分析与解决方案

核心问题:请求头被完全覆盖

你的请求拦截器中,这行代码直接替换了整个请求头对象:

config.headers = {
  Authorization: `Bearer ${authStore.user.accessToken}`,
};

原请求的Content-Type等头信息会被彻底清空,重试时自然无法保留正确的Content-Type。

修复步骤

1. 保留原有请求头,仅追加Authorization

修改请求拦截器的头信息设置逻辑,改为扩展而非替换headers:

axios.interceptors.request.use(
  (config) => {
    const authStore = useAuthStore();
    if (!authStore.loggedIn) {
      authStore.setUserFromStorage();
      if (!authStore.loggedIn) {
        return config;
      }
    }
    if (config?.headers && authStore.user.accessToken) {
      // 不要直接替换headers,而是追加Authorization字段
      config.headers.Authorization = `Bearer ${authStore.user.accessToken}`;
      // 如果担心headers不存在,也可以用Object.assign兜底
      // config.headers = Object.assign({}, config.headers, {
      //   Authorization: `Bearer ${authStore.user.accessToken}`
      // });
    }
    return config;
  },
  (error) => Promise.reject(error)
);

2. 确保重试时请求体的序列化状态

Axios在首次请求时会自动序列化JSON请求体并设置Content-Type: application/json,但err.config中的data可能已经是序列化后的字符串。重试时需要确认config.headers中存在正确的Content-Type,如果没有可以手动补充:
在重试请求前添加:

// 重试前检查并补全Content-Type
if (!err.config.headers['Content-Type']) {
  err.config.headers['Content-Type'] = 'application/json';
}
resolve(axios(err.config));

优化你的令牌刷新实现

改用实例拦截器而非全局拦截器

你创建了自定义的api实例,但拦截器挂载在了全局axios上,这会导致全局所有axios请求都受影响。应该改为给你的api实例添加拦截器:

// 在创建api实例的文件中添加拦截器
api.interceptors.request.use(/* ... */);
api.interceptors.response.use(/* ... */);

用Promise队列替代定时器轮询

轮询的方式不够优雅,可以用一个全局Promise队列来等待令牌刷新完成:

// 在authStore中添加一个存储等待队列的变量
// 比如:pendingRequests: Array<(token: string) => void> = [];

// 修改响应拦截器的等待逻辑
} else {
  // 非首个请求,加入等待队列
  return new Promise((resolve) => {
    authStore.pendingRequests.push((token) => {
      err.config.headers.Authorization = `Bearer ${token}`;
      resolve(api(err.config));
    });
  });
}

// 令牌刷新成功后,遍历队列执行所有等待的请求
authStore.setUserInfo(res.data as User);
authStore.pendingRequests.forEach(callback => callback(res.data.accessToken));
authStore.pendingRequests = [];

这样可以避免定时器的性能损耗,逻辑更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 05:33:17