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

部署Vercel后React私有路由重定向至首页问题求助

问题分析

你遇到的Vercel部署后私有路由被强制跳转到首页的问题,核心是初始加载时的状态竞态:

  • 应用启动时isAuthenticated初始值为null,ProtectedLayout会把null当成未认证状态,直接重定向到/login。
  • 紧接着AuthenticationHandler的useEffect执行,检测到sessionStorage里的bbuid后把isAuthenticated设为true,但此时路由已经被改成/login了,触发代码里的“当前是/login则跳回首页”逻辑,把你原本要访问的私有路由(比如/edit-user)覆盖了。

本地环境因为资源加载快、缓存等原因,这个竞态问题不明显,所以没暴露出来。

修复步骤

1. 给ProtectedLayout加加载状态,避免过早重定向

修改ProtectedLayout.tsx,当isAuthenticated还在null(也就是认证状态还没确定)时,不做重定向,先显示加载内容:

interface ProtectedLayoutProps {
  isAuthenticated: boolean | null;
}

const ProtectedLayout: React.FC<ProtectedLayoutProps> = ({ isAuthenticated }) => {
  // 认证状态未确定时,显示加载中
  if (isAuthenticated === null) {
    return <div>加载中...</div>; // 换成你自己的加载组件也行
  }

  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }

  return (
    <div>
      <Outlet />
    </div>
  );
};

export default ProtectedLayout;

2. 调整AuthenticationHandler的跳转逻辑,保留原路径

修改AuthenticationHandler.tsx,只有当用户当前在/login页面时才跳回首页,其他私有路由保持原样:

import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

interface Props {
  setIsAuthenticated: (authState: boolean) => void;
}

const AuthenticationHandler: React.FC<Props> = ({ setIsAuthenticated }) => {
  const navigate = useNavigate();

  useEffect(() => {
    const checkAuthentication = () => {
      const urlParams = new URLSearchParams(window.location.search);
      const bbuid = urlParams.get("bbuid");
      const currentPath = window.location.pathname;

      if (bbuid) {
        sessionStorage.setItem("bbuid", bbuid);
        // 移除参数后跳回当前路径,不是首页
        navigate(currentPath, { replace: true });
        setIsAuthenticated(true);
      } else if (sessionStorage.getItem("bbuid")) {
        setIsAuthenticated(true);
        // 只有在/login页面时才跳回首页
        if (currentPath === "/login") {
          navigate("/", { replace: true });
        }
        // 其他私有路由不跳转,保持原路径
      } else {
        setIsAuthenticated(false);
        // 未认证且不在/login时,才跳登录页
        if (currentPath !== "/login") {
          navigate("/login", { replace: true });
        }
      }
    };

    checkAuthentication();
  }, [navigate, setIsAuthenticated]);

  return null; 
};

export default AuthenticationHandler;

3. 优化初始状态,减少竞态

在App.tsx初始化isAuthenticated时,直接读取sessionStorage的值,避免一开始就处于null状态:

import { useState } from "react";
import Home from "./pages/Home";
import Auth from "./pages/Auth";
import ProtectedLayout from "./routes/ProtectedLayout";
import AuthenticationHandler from "./components/Auth/AuthenticationHandler";
import Onboarding from "./pages/Onboarding";

const App: React.FC = () => {
  // 初始化时直接检查sessionStorage,设置初始认证状态
  const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(
    () => sessionStorage.getItem("bbuid") !== null
  );

  return (
    <Router>
      <AuthenticationHandler setIsAuthenticated={setIsAuthenticated} />

      <Routes>
        <Route path="/login" element={<Auth />} />
          
        <Route element={<ProtectedLayout isAuthenticated={isAuthenticated} />}>
          <Route path="/" element={<Home />} />
          <Route path="/edit-user" element={<Onboarding />} />
        </Route>
      </Routes>
    </Router>
  );
};

export default App;

4. 补充Vercel路由配置(防止刷新404)

在项目根目录创建vercel.json,添加重写规则,确保所有请求都指向React的入口文件:

{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 06:55:24