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

React下拉菜单LinkTo部署Tomcat后默认首页Mcd无法加载排查

问题描述

我开发了一个React页面,顶部设有导航栏,选中的页面会加载在导航栏下方。导航栏包含菜单按钮,点击后弹出菜单列表可选择不同页面,默认应加载首页Mcd。本地通过npm start运行时一切正常,但部署到Tomcat服务器后,初始加载时未显示预期的Mcd页面,反而加载404页面;点击菜单按钮可正常加载任意页面。尝试设置下拉菜单选中当前页仍无效,目前临时将通配路由"*"指向Mcd页面作为临时解决方案,请求排查代码问题。


相关代码

App.js

/*
This class is to create a navigation bar at the top of the web page.
The selected action will then be loaded in the bottom half of the web page.
*/

import React, { lazy, Suspense } from "react";
import { HashRouter, Routes, Route } from "react-router-dom";

import {Navbar, NavLayout} from "../nav/Navbar";
// This will only load the pages as needed.  Loading will be done only 1 time per page.
const Mcd = lazy(() => import ("../mcd/Mcd"));
const LocationTool = lazy(() => import ("../location/LocationTool"));
// const NoPage = lazy(() => import ("../nav/NoPage"));

/*
This is the main entry point into the web page which is divided into two rows where
the top is the navigation bar.

The Mcd is the default page.  Add new pages by adding a new Route block.

Notes:
I am using HashRouter because on the sever the refresh button causes a 404 message if
I am using the BrowserRouter.  The noPage default being displayed
on the initial load vs. expected Mcd, so the workaround is to use the Mcd page not found.
*/
function App() {

    return (
        <HashRouter>
            <Navbar />
            <Suspense fallback={<h1>Loading...</h1>}>
                <Routes>
                    <Route exact path="/" element={<NavLayout />}>
                      <Route exact index element={<Mcd />} />
                        <Route exact path="location" element={<LocationTool />} />
                        <Route exact path="*" element={<Mcd />} />
                    </Route>
                </Routes>
            </Suspense>
        </HashRouter>
    );
}
/*
This class will create the navigation bar and add a dropdown menu on the right side
for all the tool pages.
*/
import React, { useEffect, useState } from "react";
import { Outlet, Link } from "react-router-dom";

import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import { orange, purple, green } from '@mui/material/colors';

/*
    Custom theme for MenuItem.
*/
const MenuItemTheme = createTheme({
  palette: {
    primary: {
      main: purple[500],
    },
    secondary: {
      main: green[700],
    },
    background: {
      default: orange[200],
      paper: orange[200],
    },
  },
});

/*
    The is where the want page will be loaded after you select one on the dropdown menu.
*/
 const NavLayout = () => {
   return (
     <>
       <Outlet />
     </>
   )
 };

/*
    Build the navigation bar and display the connection status.
*/
function Navbar() {
  const [anchorEl, setAnchorEl] = useState(null);
  const [open, setOpen] = useState(false);
  const [navLinks, setNavLinks] = useState([]);     /* This is the list of tool pages to add to the menu. */

  /* When the page is first rendered this will go off and will will build the tool page list */
  useEffect(() => {
    const navs = [
      { name: "MC Dashboard", path: "/" },
      { name: "Location Files", path: "location" },
    ];
    setNavLinks(navs);
  }, []);

  /* when mouse moves over menu button list appears */
  const handleOpenMenu = event => {
    setAnchorEl(event.currentTarget);
    setOpen(true);
  };

  /* when mouse moves off menu button list disappears */
  const handleCloseMenu = () => {
    setAnchorEl(null);
    setOpen(false);
  };

  /* Return the source code for the navigation bar.

  To make this work, the bootstrap.mon.css and boostrap.build.min.js
  need to be added to the public/index.html.  Otherwise you will not see anything rendered.

  The menu button is based on this example:
  @see https://www.w3schools.com/bootstrap5/tryit.asp?filename=trybs_dropdown-menu-right&stacked=h
  */
    return (
    <Box sx={{ flexGrow: 1 }}>
      <AppBar position="static">
        <Toolbar>
          <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}></Typography>
          <Button
            aria-controls='menu'
            onClick={handleOpenMenu}
            disableRipple
            className="{classes.accountbutton}"
            variant="contained"
            color="secondary">
            Active
          </Button>
        </Toolbar>
      </AppBar>

      <ThemeProvider theme={MenuItemTheme}>
          <Menu
            id='menu'
            onClose={handleCloseMenu}
            anchorEl={anchorEl}
            open={open}>
            {navLinks.map((d, i) => (
                <MenuItem key={i} onClick={handleCloseMenu}>
                  <Link to={d.path}>
                    <button className="dropdown-item" type="button">
                      {d.name}
                    </button>
                  </Link>
                </MenuItem>
              ))}
          </Menu>
      </ThemeProvider>
    </Box>
  );
}

export {Navbar, NavLayout};

问题排查与修复方案

核心问题原因

  1. React Router v6的exact属性冗余:v6版本中<Routes>组件已默认实现精确匹配,手动添加exact会干扰路由匹配逻辑,导致初始根路径匹配异常。
  2. HashRouter初始路径匹配漏洞:部署到Tomcat后,初始访问路径为/项目名/,此时HashRouter的哈希值为空(即#后无内容),无法匹配到/路径下的index路由,转而触发通配路由。

修复步骤

1. 移除所有exact属性

修改App.js中的路由代码,删除所有Route上的exact:

<Routes>
  <Route path="/" element={<NavLayout />}>
    <Route index element={<Mcd />} />
    <Route path="location" element={<LocationTool />} />
    <Route path="*" element={<Mcd />} />
  </Route>
</Routes>

2. 添加初始路径重定向

在顶级路由中新增重定向规则,当哈希值为空时自动跳转到/#/,确保触发首页路由:

// 先导入Navigate组件
import { HashRouter, Routes, Route, Navigate } from "react-router-dom";

// 修改App组件内的Routes部分
<Routes>
  <Route path="" element={<Navigate to="/" replace />} />
  <Route path="/" element={<NavLayout />}>
    <Route index element={<Mcd />} />
    <Route path="location" element={<LocationTool />} />
    <Route path="*" element={<Mcd />} />
  </Route>
</Routes>

3. (可选)优化临时通配路由

后续可以恢复原404页面,只保留重定向逻辑即可解决初始加载问题,不需要依赖通配路由兜底:

// 恢复NoPage组件导入
const NoPage = lazy(() => import ("../nav/NoPage"));

// 修改通配路由
<Route path="*" element={<NoPage />} />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 15:20:29