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

Axios中如何刷新Token?拦截器处理逻辑是否正确?

你的Axios响应拦截器401处理逻辑的问题与修正方案

你的代码在非401错误的处理上符合需求,但401场景的核心逻辑存在缺失,同时还有几个细节问题,下面逐一说明:

原代码的核心问题

  • 未重新发起触发401的请求:你仅更新了默认headers,但没有重新执行最初触发401的请求,导致该请求会直接失败,无法自动重试。
  • 并发请求会重复登录:如果同时有多个请求返回401,会多次调用LoginAPI.API.Signin.run(),造成冗余的登录操作。
  • 请求拦截器错误处理遗漏return:请求拦截器的错误回调里,Promise.reject(error)没有加return,会导致错误无法正常传递到后续处理逻辑。

修正后的完整代码

import axios from "axios";
import { LoginAPI } from "../playwright/tests/login/login.api";
import { test } from "@playwright/test"
import {configEnv} from "../config/config"

test.beforeAll(async () => {
    await LoginAPI.API.Signin.run()
});
const customAxios = axios.create({
    baseURL: configEnv.apiBaseURL
});

// 标记是否正在刷新token,避免并发请求重复触发登录
let isRefreshing = false;
// 存储等待token刷新完成的请求队列
let requestQueue: any[] = [];

customAxios.interceptors.request.use(
    async (config) => {
        if (config.headers) {
            config.headers['Authorization'] = `Bearer ${LoginAPI.States.token}`;
        }
        return config;
    },
    (error) => {
        // 补充return,确保错误正常传递
        return Promise.reject(error);
    }
);

customAxios.interceptors.response.use(
    function(response) {
      return response;
    },
   async function(error) {
      // 处理网络错误或无响应的异常情况
      if (!error.response) {
        return Promise.reject(error.message || '网络请求异常');
      }

      if (401 === error.response.status) {
        if (!isRefreshing) {
            isRefreshing = true;
            try {
                // 重新登录获取新token
                await LoginAPI.API.Signin.run();
                const newToken = LoginAPI.States.token;
                // 更新全局默认headers
                customAxios.defaults.headers.common['Authorization'] = `Bearer ${newToken}`;
                
                // 重试队列中所有等待的请求
                requestQueue.forEach(callback => callback(newToken));
                requestQueue = [];
            } catch (loginError) {
                // 登录失败时,拒绝队列中所有请求
                requestQueue.forEach(callback => callback(null));
                requestQueue = [];
                return Promise.reject(loginError);
            } finally {
                isRefreshing = false;
            }
        }

        // 将当前请求加入队列,等待token刷新完成后重试
        return new Promise((resolve, reject) => {
            requestQueue.push((newToken: string | null) => {
                if (newToken) {
                    // 修改原请求的headers
                    error.config.headers['Authorization'] = `Bearer ${newToken}`;
                    // 重新发起原请求
                    resolve(customAxios(error.config));
                } else {
                    reject('登录失败,无法重试请求');
                }
            });
        });
      } else {
        // 非401错误,返回error.response.data
        return Promise.reject(error.response.data);
      }
    }
);

export default customAxios

关键修正点说明

  1. 添加token刷新锁与请求队列:用isRefreshing避免并发请求重复触发登录,用requestQueue暂存等待刷新的请求,登录完成后统一重试,减少冗余操作。
  2. 重新发起原请求:token刷新成功后,修改原请求的Authorization头,调用customAxios(error.config)重新发送请求,并通过Promise返回结果,让原请求的调用链能正常接收响应。
  3. 兼容网络错误场景:增加!error.response的判断,处理网络异常等无响应状态的错误。
  4. 修复请求拦截器错误处理:在请求拦截器的错误回调中补充return,确保错误能正常传递到后续的catch逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 15:05:21