为何浏览器未跳转到/login页面?React Router 6.4.2拦截器问题
问题解决:统一处理Axios 401未授权跳转(React Router v6.4.2)
首先说你当前代码里的两个问题:
- 拦截器里用
redirect("/login")完全无效,redirect是React Router专门给loader/action函数设计的返回值,在Axios拦截器这种普通异步函数里返回它根本触发不了页面跳转。 - 每次调用
fetch函数都会新增一个Axios响应拦截器,多次调用后会堆一堆拦截器实例,导致逻辑重复执行。
你完全不需要在每个组件里单独检查响应状态,用下面两种方案就能统一处理401跳转:
方案1:全局保存navigate实例
这种方法能让你在React组件外直接调用导航方法,不用每个组件单独处理。
- 新建一个全局导航管理文件(比如
src/utils/navigate.js):
let navigateInstance; export const setNavigate = (navigate) => { navigateInstance = navigate; }; export const getNavigate = () => navigateInstance;
- 在根组件里初始化全局navigate:
import { useEffect } from 'react'; import { useNavigate, Outlet } from 'react-router-dom'; import { setNavigate } from './utils/navigate'; function Root() { const navigate = useNavigate(); useEffect(() => { setNavigate(navigate); }, [navigate]); return <Outlet />; }
- 修改你的Axios请求函数,统一处理401:
把拦截器移到函数外面,只注册一次,同时用全局navigate实例跳转:
import axios from "axios"; import { getNavigate } from "./utils/navigate"; // 只注册一次响应拦截器,避免重复执行 axios.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { console.log("Unauthorized"); // 记得清除本地的token等认证信息 localStorage.removeItem('authToken'); // 调用全局navigate跳转登录页 getNavigate()('/login'); } return Promise.reject(error); } ); const fetch = async (data, method, url, responseType, header) => { const requestObj = { method, url }; if (method.toLowerCase() === "get") { requestObj.params = data; } else { requestObj.data = data; } if (responseType) { requestObj.responseType = responseType; } if (header) { requestObj.headers = header; } const result = await axios(requestObj); return result; } export default fetch;
方案2:用自定义事件总线
要是不想暴露全局navigate实例,就用自定义事件触发导航逻辑。
- 修改Axios拦截器,触发自定义事件:
axios.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { console.log("Unauthorized"); localStorage.removeItem('authToken'); // 触发自定义的未授权事件 window.dispatchEvent(new CustomEvent('unauthorized')); } return Promise.reject(error); } );
- 在根组件里监听事件并处理导航:
import { useEffect } from 'react'; import { useNavigate, Outlet } from 'react-router-dom'; function Root() { const navigate = useNavigate(); useEffect(() => { const handleUnauthorized = () => { navigate('/login'); }; window.addEventListener('unauthorized', handleUnauthorized); // 组件卸载时记得移除监听,避免内存泄漏 return () => { window.removeEventListener('unauthorized', handleUnauthorized); }; }, [navigate]); return <Outlet />; }
总结
不管用哪种方案,都能在Axios拦截器里统一处理401跳转,不用每个组件都写一遍检查逻辑,同时还能解决拦截器重复注册的问题。
内容的提问来源于stack exchange,提问作者The KNVB
相关产品推荐
相关产品推荐

