React Router 6会话过期时,触发事件后跳转落地页的实现方案
解决方案
要解决会话过期后未刷新页面触发事件无响应的问题,核心是全局拦截API请求错误并统一处理跳转,同时优化权限校验逻辑,确保任何操作触发的会话过期都能被捕获。
1. 全局Axios拦截器统一处理401错误
所有API请求都通过封装的Axios实例发起,拦截响应中的401(会话过期/未授权)状态,直接清除本地状态并跳转落地页。
import axios from 'axios'; import { store } from './store'; // 你的Redux Store import { LOGOUT_USER } from './actionTypes'; // 清除用户状态的action类型 // 创建带配置的Axios实例 const api = axios.create({ baseURL: BASE_URL, withCredentials: true }); // 响应拦截器:捕获会话过期错误 api.interceptors.response.use( response => response, error => { if (error.response?.status === 401) { // 清除本地存储和Redux用户状态 localStorage.removeItem('id'); store.dispatch({ type: LOGOUT_USER }); // 跳转落地页(直接用location.href避免组件外无法调用useNavigate的问题) window.location.href = '/landingPage'; } return Promise.reject(error); } ); export default api;
2. 优化用户状态校验逻辑
用Redux中的用户状态替代localStorage判断权限,避免本地存储不一致导致的校验失效。
修正getCurrentUser Action
import api from './api'; // 使用上面封装的Axios实例 export const getCurrentUser = () => async (dispatch) => { try { const res = await api.get(GET_CURRENT_USER); localStorage.setItem('id', res.data.id); dispatch({ type: GET_CURRENT_USER, payload: res.data }); return res.data; } catch (err) { console.log(err); if (err.response?.status === 401) { localStorage.removeItem('id'); dispatch({ type: LOGOUT_USER }); window.location.href = '/landingPage'; } } };
优化PrivateOutlet组件
import { useState, useEffect } from 'react'; import { Outlet, Navigate } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; import { getCurrentUser } from './actions'; export default function PrivateOutlet() { const [isLoaded, setIsLoaded] = useState(false); const dispatch = useDispatch(); // 从Redux获取当前用户状态 const currentUser = useSelector(state => state.auth.currentUser); useEffect(() => { dispatch(getCurrentUser()) .finally(() => setIsLoaded(true)) // 无论成功失败都标记加载完成 }, [dispatch]); if (!isLoaded) return null; // 可替换为加载动画组件 return currentUser ? <Outlet /> : <Navigate to="/landingPage" replace />; }
3. 非API事件的权限校验(可选)
如果存在不触发API的操作(如纯本地状态修改),可以封装自定义Hook快速校验权限:
import { useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; export const useAuthCheck = () => { const currentUser = useSelector(state => state.auth.currentUser); const navigate = useNavigate(); return () => { if (!currentUser) { navigate('/landingPage', { replace: true }); return false; } return true; }; };
在组件中使用:
const checkAuth = useAuthCheck(); const handleButtonClick = () => { if (!checkAuth()) return; // 执行后续操作 };
关键注意事项
- 所有API请求必须使用封装的Axios实例,确保错误被全局拦截
- 优先用Redux状态判断登录状态,避免
localStorage被篡改或不一致的问题 - 跳转时使用
replace模式,避免用户回退到过期页面
内容的提问来源于stack exchange,提问作者SubrataG
相关产品推荐
相关产品推荐

