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

React Protected Route鉴权路由重复调用checkauth接口问题排查

问题根因

你遇到的重复请求和路由打包逻辑无关,核心是以下3个代码问题导致:

  • 鉴权请求未做副作用隔离:你直接把axios请求写在了ProtectedRoute的组件函数体中,没有包裹在useEffect钩子内。每次组件渲染都会执行一次请求,而请求返回后调用setUser、setIsAuthenticated、setGotResponse都会触发组件重渲染,进而再触发新的请求,形成无限循环。
  • 多实例重复触发:你在App.js中声明了4个ProtectedRoute组件,每个都是独立的实例,初始化阶段就会各自触发一次鉴权请求,叠加循环逻辑后请求量会指数级上升。
  • ContextProvider位置错误:你把UserContext.Provider放在了Switch内部,每次user状态更新时,Provider的value变化会触发所有子路由组件全量重渲染,进一步放大请求次数。
修复方案

按以下步骤调整即可解决:

  1. 给鉴权请求加useEffect隔离,保证仅全局触发一次请求,同时添加请求取消逻辑避免内存泄漏
  2. 把鉴权状态提升到App层统一管理,所有ProtectedRoute共享全局鉴权状态,避免多实例重复发请求
  3. 把UserContext.Provider移到Switch外层,避免不必要的子组件重渲染
调整后的代码示例

1. 修改ProtectedRoute.js

import React, { useContext } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { UserContext } from '../functions/UserContext';

const ProtectedRoute = ({ component: Component, ...rest }) => {
  const { isAuthenticated, gotResponse } = useContext(UserContext);

  if (gotResponse === 1) {
    return (
      <Route
        {...rest}
        render={(props) => {
          if (isAuthenticated === 1) {
            return <Component {...rest} {...props} />;
          } else {
            return (
              <Redirect
                to={{
                  pathname: '/login',
                  state: {
                    from: props.location,
                  },
                }}
              />
            );
          }
        }}
      />
    );
  } else {
    return null;
  }
};

export default ProtectedRoute;

2. 修改App.js

import axios from 'axios';
import { useState, useEffect } from 'react';
import { UserContext } from '../functions/UserContext';

function App() {
  const [user, setUser] = useState();
  const [isAuthenticated, setIsAuthenticated] = useState(0);
  const [gotResponse, setGotResponse] = useState(0);

  // 全局仅执行一次鉴权请求
  useEffect(() => {
    const source = axios.CancelToken.source();
    axios
      .post(
        process.env.REACT_APP_API_URL + '/api/auth/checkauth/',
        { content: 'checkAuthStatus' },
        {
          headers: { 'Content-Type': 'application/json' },
          withCredentials: true,
          cancelToken: source.token
        }
      )
      .then((res) => {
        setUser(res.data.firstName + ' ' + res.data.lastName);
        setIsAuthenticated(1);
        setGotResponse(1);
      })
      .catch(function (error) {
        if (!axios.isCancel(error)) {
          setIsAuthenticated(0);
          setGotResponse(1);
        }
      });
    // 组件卸载时取消未完成的请求
    return () => source.cancel();
  }, []);

  return (
    <UserContext.Provider value={{ user, setUser, isAuthenticated, gotResponse }}>
      <main>
        <Switch>
          <Route
            exact
            path="/login"
            render={(props) => <Login {...props} />}
          ></Route>
          <ProtectedRoute
            exact
            path="/account"
            component={Account}
            title="Account"
          ></ProtectedRoute>
          <ProtectedRoute
            exact
            path="/staff"
            component={Staff}
          ></ProtectedRoute>
          <ProtectedRoute
            exact
            path="/security"
            component={Security}
          ></ProtectedRoute>
          <ProtectedRoute exact path="/" component={Home}></ProtectedRoute>

          <Route exact path="/2fa" component={Tfa}></Route>
          <Route component={NotFound}></Route>
        </Switch>
      </main>
    </UserContext.Provider>
  );
}

export default App;

内容的提问来源于stack exchange,提问作者Sam Clay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 21:09:03