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

Axios拦截器遇401时setToken无法置空,请求排查问题

问题排查:401状态码时setToken()未生效的原因及修复方案

核心错误原因

  • React Hook使用违规:useAuthContext()是React自定义Hook,必须在React组件或其他自定义Hook的顶层调用。你在axios拦截器(组件外的普通JS函数)中调用它,违反了React Hook规则,此时获取到的setToken是Context的默认空函数,而非AuthContextProvider中定义的真实函数,所以调用后毫无效果。

代码问题拆解

axiosConfig.js中的违规调用

axiosClient.interceptors.response.use(
    (response) => {
        return response;
    },
    (error) => {
        const { response } = error;
        if (error.message === "Network Error") {
            alert("network error");
        }
        if (response.status === 401) {
            const{setToken} = useAuthContext(); // ❌ 组件外调用Hook,获取的是默认空函数
            alert('unauthorized');
            localStorage.removeItem("ACCESS_TOKEN");
            setToken();
        }
        throw error;
    }
);

AuthContextProvider.jsx逻辑无问题,但无法被组件外代码直接调用Hook

你的Context定义和setToken逻辑是正确的,但Hook的调用场景限制导致拦截器无法获取到有效函数。

修复方案

方案1:将拦截器迁移到React组件内(推荐)

在全局组件(如App)中通过useEffect挂载拦截器,此时可合法调用Hook:

import { useEffect } from 'react';
import { useAuthContext } from './AuthContextProvider';
import axiosClient from './axiosConfig';

function App() {
  const { setToken } = useAuthContext();

  useEffect(() => {
    const interceptor = axiosClient.interceptors.response.use(
      (response) => response,
      (error) => {
        const { response } = error;
        if (error.message === "Network Error") {
          alert("network error");
        }
        if (response?.status === 401) {
          alert('unauthorized');
          setToken(null); // 直接调用有效setToken,内部已自动处理localStorage清除
        }
        throw error;
      }
    );

    // 组件卸载时移除拦截器,避免内存泄漏
    return () => axiosClient.interceptors.response.eject(interceptor);
  }, [setToken]);

  // ...其他组件渲染逻辑
}

注意:无需手动调用localStorage.removeItem,你的setToken函数内部已经处理了这个逻辑。

方案2:通过全局回调传递setToken

如果不想迁移拦截器,可在Context初始化时将setToken挂载到全局对象(注意安全风险):

  1. 修改AuthContextProvider.jsx:
export const AuthContextProvider = ({ children }) => {
    const [user, setUser] = useState({});
    const [token, _setToken] = useState(localStorage.getItem('ACCESS_TOKEN'));

    const setToken = (token) => {
        _setToken(token)
        if (token) {
            localStorage.setItem('ACCESS_TOKEN', token);
        } else {
            localStorage.removeItem('ACCESS_TOKEN');
        }
    }

    // 将setToken挂载到全局window对象
    useEffect(() => {
      window.__authSetToken = setToken;
      return () => delete window.__authSetToken;
    }, [setToken]);

    return (
        <AuthContext.Provider value={{
            user,
            token,
            setUser,
            setToken
        }}>
            {children}
        </AuthContext.Provider>
    )
}
  1. 修改axiosConfig.js:
axiosClient.interceptors.response.use(
    (response) => {
        return response;
    },
    (error) => {
        const { response } = error;
        if (error.message === "Network Error") {
            alert("network error");
        }
        if (response.status === 401) {
            alert('unauthorized');
            // 调用全局挂载的有效setToken
            window.__authSetToken?.call(null, null);
        }
        throw error;
    }
);

该方案需注意全局变量的安全性,生产环境谨慎使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 18:52:49