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

Nginx无法识别React应用路由,请求配置指导

React Router + Nginx 部署路由问题排查与解决

问题场景

基于create-react-app创建的React应用,使用react-router-dom做路由管理。通过Dockerfile.dev构建运行容器时,访问/mail路径能正常显示消息表格(数据来自/data/Messages.ts和/data/Config.ts)。但用Nginx部署时(通过Dockerfile.prod构建镜像,命令docker build -f Dockerfile.prod -t ui-nginx .,运行命令docker run -p 8080:80 ui-nginx),访问/mail仅显示空表格,且Nginx日志中没有/mail的请求记录。已尝试修改package.json的basename、在Dockerfile中设置ENV PUBLIC_URL=http://localhost:8080/、调整nginx.conf配置等方案,均未解决,需指导配置Nginx支持/mail路由导航。

问题分析与解决方案

核心定位

Nginx日志无/mail请求,说明访问/mail时Nginx已通过try_files规则将请求转发至index.html,前端路由已接管请求。空表格问题并非Nginx路由配置错误,而是生产构建后的数据加载逻辑异常。

排查与修复步骤

  1. 确认静态数据是否被打包
    create-react-app生产构建仅打包public目录静态资源和src中被代码引用的文件。检查/data/Messages.ts和/data/Config.ts是否在MailView等组件中被正确导入,确保它们被包含在构建产物内:

    // 示例:确保导入路径正确
    import { messages } from '../../data/Messages';
    import { user } from '../../data/Config';
    
  2. 验证生产构建产物
    进入运行的Nginx容器,检查主JS文件是否包含数据内容:

    docker exec -it <容器ID> /bin/sh
    cat /usr/share/nginx/html/static/js/main.*.js | grep "messages"
    
    • 若能搜索到数据:问题出在前端组件渲染逻辑,检查浏览器控制台是否有JS报错。
    • 若搜索不到:数据文件未被正确引入,需修正导入逻辑。
  3. 修正无效配置

    • 无需设置PUBLIC_URL=http://localhost:8080/,应用部署在根路径下,默认配置即可。
    • 无需修改package.json的basename,仅当应用部署在子路径时才需要该配置。
  4. 确认Nginx配置有效性
    当前nginx.conf已正确支持React浏览器路由,无需修改:

    server {
      listen 80;
    
      location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
      }
    
      error_page   500 502 503 504  /50x.html;
    
      location = /50x.html {
        root   /usr/share/nginx/html;
      }
    }
    

附:相关配置与日志

Docker日志

% docker run -p 8080:80 ui-nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf differs from the packaged version
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/02/24 19:35:53 [notice] 1#1: using the "epoll" event method
2024/02/24 19:35:53 [notice] 1#1: nginx/1.24.0
2024/02/24 19:35:53 [notice] 1#1: built by gcc 12.2.1 20220924 (Alpine 12.2.1_git20220924-r4) 
2024/02/24 19:35:53 [notice] 1#1: OS: Linux 6.6.12-linuxkit
2024/02/24 19:35:53 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2024/02/24 19:35:53 [notice] 1#1: start worker processes
2024/02/24 19:35:53 [notice] 1#1: start worker process 29
2024/02/24 19:35:53 [notice] 1#1: start worker process 30
2024/02/24 19:35:53 [notice] 1#1: start worker process 31
2024/02/24 19:35:53 [notice] 1#1: start worker process 32
2024/02/24 19:35:53 [notice] 1#1: start worker process 33
2024/02/24 19:35:53 [notice] 1#1: start worker process 34
2024/02/24 19:35:53 [notice] 1#1: start worker process 35
2024/02/24 19:35:53 [notice] 1#1: start worker process 36
192.168.65.1 - - [24/Feb/2024:19:36:29 +0000] "GET / HTTP/1.1" 200 887 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" "-"
192.168.65.1 - - [24/Feb/2024:19:36:29 +0000] "GET /static/js/main.391febc6.js HTTP/1.1" 200 223526 "http://localhost:8080/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" "-"
192.168.65.1 - - [24/Feb/2024:19:36:29 +0000] "GET /static/css/main.cb0cc79e.css HTTP/1.1" 200 4141 "http://localhost:8080/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" "-"
192.168.65.1 - - [24/Feb/2024:19:36:29 +0000] "GET /manifest.json HTTP/1.1" 200 306 "http://localhost:8080/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" "-"

项目结构

Dockerfile.prod
README.md
docker-compose.prod.yml
nginx
└── nginx.conf
node_modules
package-lock.json
package.json
public
├── delete.png
├── favicon.ico
├── index.html
├── manifest.json
└── robots.txt
src
├── App.css
├── App.test.tsx
├── App.tsx
├── components
│   ├── Box.tsx
│   ├── Button.tsx
│   ├── Checkbox.tsx
│   ├── FlexBox.tsx
│   ├── Footer.tsx
│   ├── Header.tsx
│   ├── Home.tsx
│   ├── Icons
│   │   ├── CellControl.tsx
│   │   └── Delete.tsx
│   ├── Link.tsx
│   ├── Mail
│   │   ├── Mail.tsx
│   │   ├── MailReply.tsx
│   │   ├── MailSent.tsx
│   │   ├── MailView.tsx
│   │   ├── MessageNew.tsx
│   │   ├── MessageReadMetaHeader.tsx
│   │   ├── MessageView.tsx
│   │   └── Table
│   │       ├── Table.tsx
│   │       ├── TableHeaders.tsx
│   │       └── TableRows.tsx
│   ├── NotFound.tsx
│   ├── Select.tsx
│   ├── TextArea.tsx
│   ├── TextAreaImageAdd.tsx
│   ├── TextField.tsx
│   ├── TextFieldImageAdd.tsx
│   └── Typography.tsx
├── data
│   ├── Config.ts
│   ├── Constants.ts
│   ├── Messages.ts
├── index.css
├── index.tsx
├── react-app-env.d.ts
├── reportWebVitals.ts
├── setupTests.ts
├── tests
│   ├── Button.test.tsx
│   ├── Header.test.tsx
│   ├── Home.test.tsx
│   ├── Mail.test.tsx
│   └── Select.test.tsx
├── types
│   └── types.tsx
└── utils
    └── utils.tsx
tsconfig.json

nginx.conf

server {

  listen 80;

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  error_page   500 502 503 504  /50x.html;

  location = /50x.html {
    root   /usr/share/nginx/html;
  }

}

Dockerfile.prod

FROM node:21-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY public  /app/public
COPY package.json package-lock.json /app/
RUN npm ci
COPY . ./
RUN npm run build

FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

App.tsx

import './App.css';
import { Route, Routes } from 'react-router-dom';
import { StringConstants } from "./data/Constants";
import { Footer } from './components/Footer';
import { Header } from './components/Header';
import { Home } from './components/Home';
import { MailReply } from "./components/Mail/MailReply";
import { MailSent } from "./components/Mail/MailSent";
import { MailView } from "./components/Mail/MailView";
import { useState } from "react";
import { user } from "./data/Config";
import NotFound from "./components/NotFound";


function App() {
  const [mailFactor, setMailFactor] = useState<number>(-1)
  const [userLoggedIn] = useState<boolean>(false)

  return (
    <div className="App">
      <Header setMailFactor={setMailFactor} userLoggedIn={userLoggedIn} />
      <Routes>
        <Route path="/" element={ <Home /> } />
        <Route path="mail" >
          <Route index          element={<MailView title={StringConstants.INBOX} mailFactor={mailFactor} setMailFactor={setMailFactor} />} />
          <Route path="sent"    element={<MailView title={StringConstants.SENT} mailFactor={mailFactor} setMailFactor={setMailFactor} />} />
          <Route path="deleted" element={<MailView title={StringConstants.DELETED} mailFactor={mailFactor} setMailFactor={setMailFactor} />} />
          <Route path="new"     element={<MailView title={StringConstants.BUTTON_TEXT_NEW} mailFactor={mailFactor} setMailFactor={setMailFactor} />} />
          <Route path="send"    element={<MailSent />} />
          <Route path="reply"   element={<MailReply />} />
        </Route>
        <Route path='*'         element={<NotFound />}/>
      </Routes>
      <Footer />
    </div>
  );
}

export default App;

Dockerfile.dev

FROM node:20-alpine as build
WORKDIR /app
COPY public  /app/public
COPY package.json package-lock.json /app/
ENV PATH /app/node_modules/.bin:$PATH

RUN npm ci
COPY . ./

CMD ["npm", "start"]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:39:53