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

Axios拦截器无法重发失败请求问题排查

问题分析与解决方案

核心问题

你当前的代码有两个关键问题导致重发请求不生效:

  1. 未等待刷新token的异步操作完成:store.dispatch(refresh({}))是异步操作,但你直接在它后面调用重发请求,此时新的access token还没更新到Redux store里,refresh请求甚至可能还没完成,重发逻辑自然无法正常工作。
  2. 缺少防重复刷新机制:如果多个请求同时因token过期失败,会多次触发refresh请求,造成不必要的后端请求,也可能导致逻辑混乱。

另外注意变量名拼写错误:orginalRequest应该是originalRequest(语法上不报错,但属于不良编码习惯,建议修正)。

修正后的代码

创建实例与拦截器

import axios from 'axios';
import { store } from '../../../app/store';
import { refresh } from '../../auth/authSlice';

const axiosInstance = axios.create({
    timeout: 5000
})
axiosInstance.defaults.baseURL = process.env.REACT_APP_BASE_SCRAPE_URL
axiosInstance.defaults.withCredentials = true;

// 防重复刷新标志
let isRefreshing = false;
// 存储等待重发的请求队列
let failedRequestsQueue = [];

axiosInstance.interceptors.request.use(function(config){    
    const state = store.getState();
    const token = state.auth.accessToken;
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
})

axiosInstance.interceptors.response.use(resp => resp, async error => {
    const originalRequest = error.config; // 修正拼写错误

    // 仅处理token过期的情况,排除refresh请求本身避免死循环
    if (error.response?.data === "Invalid Access Token" && !originalRequest._retry) {
        originalRequest._retry = true; // 标记已重试,防止死循环

        if (!isRefreshing) {
            isRefreshing = true;
            try {
                // 等待refresh异步action完成,确保token已更新到store
                await store.dispatch(refresh({})).unwrap();
                // 刷新完成后,批量重发队列中所有等待的请求
                failedRequestsQueue.forEach(request => request.resolve(axiosInstance(request.config)));
                failedRequestsQueue = [];
            } catch (refreshError) {
                // 刷新失败,拒绝所有等待的请求
                failedRequestsQueue.forEach(request => request.reject(refreshError));
                failedRequestsQueue = [];
                // 这里可以添加登录页跳转等错误处理逻辑
                window.location.href = '/login';
            } finally {
                isRefreshing = false;
            }
        }

        // 将当前请求加入队列,等待token刷新后重发
        return new Promise((resolve, reject) => {
            failedRequestsQueue.push({ resolve, reject, config: originalRequest });
        });
    }

    // 其他错误直接抛出
    return Promise.reject(error);
})

export default axiosInstance

关键修正点说明

  1. 等待refresh完成:用await store.dispatch(refresh({})).unwrap()确保token完全更新到store后再处理重发,unwrap()用于捕获异步thunk的成功/失败状态。
  2. 请求队列与防重复:通过isRefreshing避免重复触发refresh,用队列存储所有过期请求,刷新完成后批量重发,保证所有请求都能使用新token。
  3. 重试标记:给请求添加_retry属性,防止重发后再次因token过期进入拦截器造成死循环。
  4. 拼写修正:统一变量名为originalRequest,规范编码。

验证效果

修改后,当token过期时:

  1. 第一个失败请求触发refresh
  2. 后续失败请求进入队列等待
  3. 刷新成功后,队列中所有请求自动重发,且请求头会带上新token
  4. 刷新失败时,会执行登录跳转等错误逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 13:54:52