React-Router-Dom V6+Vite构建后/contract-preview等路由404问题求助
使用 react-router-dom v6 搭配 Vite 开发单页应用,路由配置如下:
const router = createBrowserRouter([ { path: "/", element: <Container />, children: [ { index: true, element: <Home />, }, { path: "/log-in", element: <Login />, }, { path: "/contact", element: <Contact />, }, { path: "/pricing", element: <Pricing />, }, ], }, { path: "/contract-preview", element: <ContractPreview />, }, { path: "/*", element: <NotFound />, }, ]);
执行 yarn build 构建后,运行 dist 目录代码(服务器部署后情况一致),/contract-preview 路由及通配符 /* 对应的 NotFound 页面无法访问,返回服务器自定义404页面。
项目依赖版本:
"vite": "^4.0.3", "@vitejs/plugin-react": "^3.0.0", "react-router-dom": "^6.6.1", "react": "^18.2.0", "react-dom": "^18.2.0",
Vite 配置:
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()] })
这是单页应用(SPA)的典型路由问题:直接访问非根路径或刷新页面时,服务器会优先寻找对应物理文件,找不到就返回服务器自带的404,而没有交给 React Router 处理路由。解决需要从 Vite 本地预览配置 和 生产服务器配置 两方面入手:
1. 本地预览构建产物的配置
如果只是本地测试 dist 文件,在 Vite 配置中添加 preview 选项,让预览服务器把所有请求 fallback 到 index.html:
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], preview: { historyApiFallback: true // 核心配置,所有请求转发到index.html } })
之后执行 yarn preview 就能正常访问所有路由了。
2. 生产服务器配置
部署到线上服务器时,必须配置服务器将所有路由请求转发到 index.html,以下是常见服务器的配置示例:
Nginx 配置
在站点配置中添加:
location / { try_files $uri $uri/ /index.html; }
这个规则会让 Nginx 先尝试访问请求的文件/目录,找不到就返回 index.html,交给 React Router 处理路由。
Apache 配置
在项目根目录创建 .htaccess 文件,添加:
RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L]
静态托管平台(Vercel/Netlify)
这类平台自带 SPA 路由支持,只需添加简单配置文件:
- Vercel:创建
vercel.json{ "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] } - Netlify:创建
_redirects文件/* /index.html 200
3. 子路径部署的额外配置(可选)
如果应用部署在域名的子路径下(比如 https://xxx.com/my-app/),需要同步配置 Vite 和 React Router 的 base 路径:
- Vite 配置添加
base:export default defineConfig({ base: '/my-app/', plugins: [react()] }) - React Router 配置添加
basename:const router = createBrowserRouter( [/* 原有路由配置 */], { basename: '/my-app/' } )
根路径部署则无需这一步。
内容的提问来源于stack exchange,提问作者savkevip

