React项目中axios请求返回401状态码时如何实现页面重定向?
问题根因
你当前写法的核心问题是:<Redirect> 是 React 提供的声明式路由组件,仅能在 React 组件的渲染上下文(组件的render方法/函数组件返回值)中生效,你在异步请求的catch回调里返回这个组件,不会被React渲染引擎识别,自然无法触发跳转。
解决方案
推荐使用命令式history跳转的方式实现非组件上下文的路由跳转,适配你当前的异步请求+redux-thunk的架构,具体操作如下:
步骤1:抽离公共history对象
因为react-router的路由跳转能力本质是基于history库实现的,我们把history实例抽成公共模块,就可以在任意JS文件中调用跳转能力:
- 新建
src/utils/history.js文件,写入以下代码:
import { createBrowserHistory } from 'history' export default createBrowserHistory()
- 如果安装后出现版本不兼容问题,执行命令安装适配react-router v5的版本:
npm i history@4.10.1
步骤2:修改路由配置
把原来的BrowserRouter替换为基础Router,传入你自定义的history实例:
import { Router, Switch, Route } from "react-router"; import history from './utils/history' // 导入自定义history const Container = () => { return ( <div className="container"> <Router history={history}> <Switch> <Route path="/login"> <Login /> </Route> <Route path="/register"> <Login /> </Route> <Route path="/all-users"> <Alltasks /> </Route> <Route path="/all-articles"> <AllUsers /> </Route> </Switch> </Router> <ToastContainer /> </div> ); }
步骤3:修改请求逻辑
直接调用history的push方法触发跳转,不需要返回Redirect组件:
import axiosConfig from "../../config/axios"; import actions from "./actions"; import history from '../../utils/history' // 导入公共history const fetchUser = async () => { try { const response = await axiosConfig.get('api/get-user') return response.data } catch (error) { console.log(error.response.status) // 401 console.log(error.response.data.error) // Please Authenticate if (error.response.status === 401) { // 执行跳转,同时记录跳转前的路径,方便登录后跳回原页面 history.push({ pathname: '/login', state: { from: window.location.pathname } }) // 抛出错误中断后续逻辑,避免dispatch无效数据 throw new Error('用户未授权') } throw error } } export const getUser = () => async (dispatch) => { try { const user = await fetchUser() dispatch(actions.setUser(user)); } catch (err) { // 可在此处添加全局错误提示逻辑 console.error(err) } }
优化方案:全局统一处理401
你也可以直接在axios的响应拦截器里统一处理所有接口的401错误,不用每个请求单独写判断,修改你的../../config/axios配置文件即可:
import axios from 'axios' import history from '../utils/history' const axiosConfig = axios.create({ baseURL: '你的接口基础前缀', timeout: 10000 }) // 全局响应拦截器 axiosConfig.interceptors.response.use( response => response, error => { // 所有接口返回401都自动跳转登录页,同时清空本地缓存的身份信息 if (error.response?.status === 401) { localStorage.removeItem('token') localStorage.removeItem('userInfo') history.push('/login') } return Promise.reject(error) } ) export default axiosConfig
内容的提问来源于stack exchange,提问作者KaKi786
相关产品推荐
相关产品推荐

