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

React-Router-Dom V6中Axios拦截器History.push失效问题求助

问题:React Router v6中Axios拦截器跳转登录页仅修改URL不切换组件

使用react-router-dom v6开发项目时,刷新令牌(refresh token)过期后,在Axios拦截器中调用history("/login")仅修改了URL地址,但页面组件并未切换。相关代码如下:

现有代码

index.js

<Provider store={store}>
  <BrowserRouter history={history}>
    <App />
  </BrowserRouter>
</Provider>

App.js

<div className="App">
  <LoadingPage />
  <FetchProfile />
  <AlertMessages />

  <Routes>
    <Route path="/" element={<MainLayout />}>
      <Route path="/users" element={<UsersPage />} />
      <Route path="/agent" element={<AgentPage />} />
      <Route path="/server-database" element={<ServerDBPage />} />
      <Route path="/customers" element={<CustomersPage />} />
      <Route path="/agmdb" element={<AgmdbPage />} />
      <Route path="/profile" element={<ProfilePage />} />
      <Route path="/userlogs" element={<UserLogsPage />} />
    </Route>
    <Route path="/login" element={<LoginLayout />} />
  </Routes>
</div>

history.js

import { createBrowserHistory } from 'history';
const history = createBrowserHistory()
export default history;

Axios拦截器代码

axiosClient.interceptors.response.use((response) => {
    return handleResponse(response)
}, (error) => {
    const originalRequest = error.config;

    if (error.response.status === 401 && !originalRequest._retry) {
        if (isRefreshing) {
            return new Promise(function (resolve, reject) {
                failedQueue.push({ resolve, reject })
            }).then(token => {
                originalRequest.headers['Authorization'] = 'Bearer ' + token;
                return axiosClient.request(originalRequest);
            }).catch(err => {
                return Promise.reject(err);
            })
        }

        originalRequest._retry = true;
        isRefreshing = true;

        const refreshToken = LocalStorageService.getRefreshToken();

        return new Promise(function (resolve, reject) {
            axios.post(`${process.env.REACT_APP_API_URL}/auth/refreshtoken`, { refreshtoken: refreshToken })
                .then((res) => {
                    const { data } = res;
                    LocalStorageService.setToken(data.response);
                    axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.response.accessToken;
                    originalRequest.headers['Authorization'] = 'Bearer ' + data.response.accessToken;
                    processQueue(null, data.response.accessToken);
                    resolve(axiosClient.request(originalRequest));
                })
                .catch((err) => {
                    console.log(err);
                    const { status, data } = err.response;

                    if (status === 401) {
                        history("/login")   
                    }
                    if (data && (data.error.code === "REFRESH_TOKEN_INVALID")) {
                        history("/login")   
                    }
                    processQueue(err, null);
                    reject(err);
                })
                .finally(() => {
                    isRefreshing = false
                })
        })
    }
    return Promise.reject(handleError(error));
});

问题原因

react-router-dom v6的<BrowserRouter>不再接受history属性,你手动创建的history实例与路由内部维护的导航实例完全独立。调用自定义history的跳转方法只会修改浏览器URL,但无法触发路由系统的组件更新。

解决方案

方案1:使用Context共享导航方法(兼容v6全版本)

  1. 移除自定义history.js,创建导航上下文:
// NavigationContext.js
import { createContext, useContext, useNavigate } from 'react-router-dom';

const NavigationContext = createContext();

export const NavigationProvider = ({ children }) => {
  const navigate = useNavigate();
  return (
    <NavigationContext.Provider value={{ navigate }}>
      {children}
    </NavigationContext.Provider>
  );
};

export const useNavigation = () => useContext(NavigationContext);
  1. 修改index.js,移除history属性:
<Provider store={store}>
  <BrowserRouter>
    <App />
  </BrowserRouter>
</Provider>
  1. 在App.js中包裹NavigationProvider:
import { NavigationProvider } from './NavigationContext';
import { useEffect } from 'react';
import { setNavigate } from './axiosClient';
import { useNavigation } from './NavigationContext';

function App() {
  const { navigate } = useNavigation();

  useEffect(() => {
    // 将导航方法传递给Axios拦截器
    setNavigate(navigate);
  }, [navigate]);

  return (
    <NavigationProvider>
      <div className="App">
        <LoadingPage />
        <FetchProfile />
        <AlertMessages />
        <Routes>
          {/* 原有路由配置保持不变 */}
        </Routes>
      </div>
    </NavigationProvider>
  );
}
  1. 修改Axios拦截器,添加导航方法接收逻辑:
// axiosClient.js
import axios from 'axios';

export const axiosClient = axios.create({
  // 你的基础配置
});

let navigate;

export const setNavigate = (nav) => {
  navigate = nav;
};

// 拦截器代码修改跳转逻辑
axiosClient.interceptors.response.use((response) => {
    return handleResponse(response)
}, (error) => {
    // ... 原有逻辑不变
    .catch((err) => {
        console.log(err);
        const { status, data } = err.response;

        if (status === 401 || (data && data.error.code === "REFRESH_TOKEN_INVALID")) {
            // 使用共享的navigate方法跳转
            navigate("/login");
            // 清除本地令牌,避免重复触发
            LocalStorageService.clearToken();
        }
        processQueue(err, null);
        reject(err);
    })
    // ... 原有逻辑不变
});

方案2:使用RouterProvider(v6.4+推荐)

  1. 重构路由配置,使用createBrowserRouter:
// index.js
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store';
import MainLayout from './MainLayout';
import LoginLayout from './LoginLayout';
// 导入其他页面组件

const router = createBrowserRouter([
  {
    path: "/",
    element: <MainLayout />,
    children: [
      { path: "/users", element: <UsersPage /> },
      { path: "/agent", element: <AgentPage /> },
      { path: "/server-database", element: <ServerDBPage /> },
      { path: "/customers", element: <CustomersPage /> },
      { path: "/agmdb", element: <AgmdbPage /> },
      { path: "/profile", element: <ProfilePage /> },
      { path: "/userlogs", element: <UserLogsPage /> },
    ]
  },
  { path: "/login", element: <LoginLayout /> }
]);

ReactDOM.createRoot(document.getElementById('root')).render(
  <Provider store={store}>
    <RouterProvider router={router} />
  </Provider>
);
  1. 修改Axios拦截器,直接使用router实例跳转:
// axiosClient.js
import { router } from './index';

// 拦截器中替换跳转逻辑
if (status === 401 || (data && data.error.code === "REFRESH_TOKEN_INVALID")) {
    router.navigate("/login");
    LocalStorageService.clearToken();
}

内容的提问来源于stack exchange,提问作者phu.duongquoc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 03:08:27