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

Axios拦截器重复执行问题:多组件用自定义Hook日志重复

问题根源与解决方案

你的问题核心在于:每次调用useAxiosPrivate时,都给同一个Axios实例重复添加了请求拦截器,而非每个Hook实例对应独立的拦截器组。

具体原因

如果你的useAxiosPrivate复用了同一个全局Axios实例(比如通过axios.create()创建的实例被多个Hook共享),每次Hook初始化时调用instance.interceptors.request.use(),都会往该实例的拦截器队列中新增一个拦截器。随着你在更多组件中使用这个Hook,拦截器数量会不断累积,导致单次请求触发所有已添加的拦截器,日志打印次数自然递增。

验证方法

可以在添加拦截器前打印拦截器队列长度,确认累积情况:

console.log('当前请求拦截器数量:', instance.interceptors.request.handlers.length);

你会发现每次调用useAxiosPrivate时,这个数字都会+1。

解决办法

方案1:每个Hook实例创建独立Axios实例

在useAxiosPrivate内部每次都生成新的Axios实例,确保拦截器完全独立:

import { useMemo } from 'react';
import axios from 'axios';

const useAxiosPrivate = () => {
  const instance = useMemo(() => {
    const axiosInstance = axios.create({ baseURL: '/api' });
    // 给当前实例添加专属拦截器
    axiosInstance.interceptors.request.use(
      (config) => {
        console.log('请求地址:', config.url);
        // 处理token逻辑
        return config;
      },
      (error) => Promise.reject(error)
    );
    return axiosInstance;
  }, []);

  return instance;
};

方案2:添加拦截器时做去重检查

给拦截器添加唯一标识,确保同一类型的拦截器只添加一次:

import { useEffect, useRef } from 'react';
import axios from 'axios';

const useAxiosPrivate = () => {
  const instance = useRef(axios.create({ baseURL: '/api' })).current;
  const hasInterceptor = useRef(false);

  useEffect(() => {
    if (!hasInterceptor.current) {
      instance.interceptors.request.use(
        (config) => {
          console.log('请求地址:', config.url);
          // 处理token逻辑
          return config;
        },
        (error) => Promise.reject(error)
      );
      hasInterceptor.current = true;
    }
  }, [instance]);

  return instance;
};

方案3:组件卸载时移除拦截器

利用useEffect的清理函数,在组件卸载时移除对应的拦截器,避免累积:

import { useEffect, useRef } from 'react';
import axios from 'axios';

const useAxiosPrivate = () => {
  const instance = useRef(axios.create({ baseURL: '/api' })).current;
  const interceptorId = useRef(null);

  useEffect(() => {
    // 添加拦截器并保存ID
    interceptorId.current = instance.interceptors.request.use(
      (config) => {
        console.log('请求地址:', config.url);
        // 处理token逻辑
        return config;
      },
      (error) => Promise.reject(error)
    );

    // 组件卸载时移除拦截器
    return () => {
      if (interceptorId.current) {
        instance.interceptors.request.eject(interceptorId.current);
      }
    };
  }, [instance]);

  return instance;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 01:49:52