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

自定义Hook中带Token的Axios实例仅首次请求有效问题求助

问题分析与解决方案

问题根源

你的自定义Hook存在以下核心问题:

  • 未缓存Axios实例:每次调用useAxiosAuthenticated都会创建新的Axios实例,组件重新渲染时会生成新实例,若业务逻辑复用了旧实例,会出现拦截器未正确配置的情况,导致后续请求无法携带有效Token。
  • 拦截器未清理:多次添加拦截器且未做清理,可能引发内存泄漏,甚至导致请求逻辑异常。
  • 存入state的异步问题:将Axios实例存入state时,由于state更新是异步的,组件首次渲染时无法获取到已配置拦截器的实例,直接触发401错误。

修正后的Hook实现

import { useAuth0 } from "@auth0/auth0-react";
import axios, { AxiosInstance } from "axios";
import { useEffect, useMemo } from "react";

export default function useAxiosAuthenticated() {
  const { getAccessTokenSilently } = useAuth0();

  // 用useMemo缓存Axios实例,仅当依赖变化时重新创建
  const axiosInstance = useMemo(() => {
    const instance = axios.create({
      baseURL: GeneralHelper.APIUrl,
    });

    // 添加请求拦截器并记录ID,用于后续清理
    const interceptorId = instance.interceptors.request.use(
      async (config) => {
        const token = await getAccessTokenSilently();
        config.headers.Authorization = `Bearer ${token}`;
        return config;
      },
      (error) => Promise.reject(error)
    );

    return { instance, interceptorId };
  }, [getAccessTokenSilently]);

  // 组件卸载时清理拦截器,避免内存泄漏
  useEffect(() => {
    const { instance, interceptorId } = axiosInstance;
    return () => {
      instance.interceptors.request.eject(interceptorId);
    };
  }, [axiosInstance]);

  return axiosInstance.instance;
}

关键修正点说明

  1. 缓存实例:通过useMemo缓存Axios实例,仅在getAccessTokenSilently变化时重新创建,确保实例的稳定性,避免组件渲染时重复生成实例。
  2. 拦截器生命周期管理:添加拦截器时记录ID,在组件卸载时调用eject清理,避免内存泄漏和重复拦截逻辑。
  3. 直接返回就绪实例:无需将实例存入state,组件调用Hook时即可获取已配置好拦截器的实例,保证首次请求就能正常携带Token。

使用方式

在组件中直接调用Hook获取实例即可,无需额外配置:

const axiosAuth = useAxiosAuthenticated();

// 发起请求
axiosAuth.get("/api/data")
  .then(res => console.log(res.data))
  .catch(err => console.error(err));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 07:00:58