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

Axios重试请求丢失Headers问题排查求助

问题描述

基于Axios创建API请求实例,请求拦截器自动添加Bearer授权头;响应拦截器捕获401(Token过期)响应时,通过刷新机制获取新Token并重试原请求。但重试时发现Axios自动生成的Content-Type等Headers丢失,导致后端API无法正常识别请求。

注:未手动设置Content-Type,该头由Axios自动生成,困惑为何重试时这些头会丢失。

相关代码:

const api = axios.create({
  baseURL: "https://www.mycoolapi.com",
  timeout: 5000,
  withCredentials: true,
});

api.interceptors.request.use((config) => {
    // Add the auth header (not messing with any other headers)
    config.headers!.Authorization = `Bearer ${accessToken}`;
    return config;
  }, (error) => Promise.reject(error));

api.interceptors.response.use((response) => response,
  async (error) => {
    if (error.response.status == 401 && refreshToken && !error.config._isRetry) {
      // Token expired? Refresh, then retry the original request
      error.config._isRetry = true;
      await refreshLogIn();
      return api(error.config);
    }
  
    throw error;
  });

async function refreshLogIn() {
  // Use the refresh token to get a new token pair
  const response = await api.post( "/token",
    new URLSearchParams({
      grant_type: "refresh_token",
      refresh_token: refreshToken,
    })
  );

  accessToken = response.data["access_token"];
  refreshToken = response.data["refresh_token"];
}

调试发现:响应拦截器中准备重试的error.config包含完整Headers,但进入请求拦截器重试时,Content-Type及Symbol(defaults)中的内容已丢失。


问题原因与解决方法

核心原因

直接复用error.config发起重试请求时,Axios不会重新触发默认的头信息处理逻辑——包括自动根据请求体生成Content-Type的逻辑。error.config里的Headers是第一次请求时的快照,但重试时原有的默认头关联(如Symbol(defaults))已失效,Axios也不会重新分析请求体来生成对应的Content-Type。

具体解决方案

方案1:重新构建请求配置

不要直接传递error.config,而是基于它创建新的配置对象,让Axios重新执行头信息处理流程:

// 替换响应拦截器中的return api(error.config);
return api({
  ...error.config,
  headers: { ...error.config.headers } // 浅拷贝原始头,避免引用冲突
});

这种方式会让Axios重新识别请求体类型,自动生成正确的Content-Type,同时保留原始请求的所有参数。

方案2:合并实例默认头(备选)

如果需要严格复用原有配置结构,可以将实例的默认头合并到error.config中:

error.config.headers = {
  ...api.defaults.headers.common,
  ...api.defaults.headers[error.config.method],
  ...error.config.headers
};
return api(error.config);

注意:这种方式仅能恢复静态默认头,无法处理Axios根据请求体动态生成的Content-Type,因此方案1更可靠。

优化:隔离刷新Token的请求

当前refreshLogIn使用自定义的api实例发起请求,可能触发自身的请求拦截器(比如添加旧的过期Token),建议改用原生Axios发起刷新请求,避免拦截器干扰:

async function refreshLogIn() {
  const response = await axios.post(
    "https://www.mycoolapi.com/token",
    new URLSearchParams({
      grant_type: "refresh_token",
      refresh_token: refreshToken,
    }),
    { withCredentials: true }
  );

  accessToken = response.data["access_token"];
  refreshToken = response.data["refresh_token"];
}

验证方式

重试时检查请求配置的headers,确认Content-Type与请求体匹配:

  • JSON请求体对应application/json
  • URLSearchParams对应application/x-www-form-urlencoded

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 15:15:45