前言
我们经常需要部署一个本地服务用于模拟线上环境进行测试,这时候就会遇到各种细节问题。
nginx安装
安装nginx有很多种方式,不同的系统可以使用对应的包管理器下载安装,这里通过homebrew安装。
安装homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
测试homebrew安装
brew -v
使用homebrew安装nginx
brew install nginx
测试nginx安装
nginx -v
启动nginx
sudo nginx
这将会直接启动nginx服务器,如果你想在后台运行,使用
sudo nginx -g "daemon off;"
关闭nginx
sudo nginx -s stop
nginx配置
找到配置文件,修改配置
nginx -t
显示的信息会提示nginx.conf文件的位置
nginx: configuration file /usr/local/etc/nginx/nginx.conf test failed
这里/usr/local/etc/nginx/nginx.conf
修改配置文件之前,建议先备份再修改。
如果配置的server_name是localhost,需要先修改hosts文件。
-
打开 Finder。
-
按下 Cmd + Shift + G 来打开“前往文件夹”窗口。
-
在弹出的对话框中输入 /private/etc/,然后点击“前往”。
-
找到 hosts 文件,右键点击它,选择“打开方式” -> “文本编辑”。
-
如果需要,输入管理员密码以允许编辑。
-
在打开的 hosts 文件中进行需要的修改。
-
保存文件。
127.0.0.1 localhost
403: permission denied
遇到nginx配置问题,先干两件事:
1、测试配置语法是否正确
sudo nginx -t
如果显示syntax is ok 和 test is succussfull,则表示配置语法正确。
2、启用日志文件logs,增加 nginx 日志配置
error_log logs/error.log;
访问之后,可以查看日志文件,一般会显示具体问题,比如某个文件拒绝访问,此时从两个方面入手:
1、修改react项目打包后的文件夹及其子目录访问权限
chmod -R 755 /path/to/directory
2、修改nginx用户配置,保证启动nginx的用户有权限访问
user xiaohong admin;
注意: 这里最好加上用户xiaohong所在用户组admin,否则可能导致权限不足。
查看当前用户
whoami
查看用户组
groups
查看特定用户所在的用户组
id -Gn 用户名
3、修改完配置记得重启nginx
sudo nginx -s reload
404: 单页应用路由接管问题
比如:当我访问 "http://localhost:8080/" 是能正常访问页面的,但是当我直接通过 "http://localhost:8080/cat" 就会出现404了
-
React 项目路由注册案例
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' import './App.css' import RootLayout from './pages/RootLayout' import Cat from './pages/Cat' import Dog from './pages/Dog'
function App() {
return ( <Route path="/" element={}> <Route index element={} /> <Route path='cat' element={} /> <Route path='dog' element={} /> ) }
export default App
问题原因
- React Router 的客户端路由原理
React Router 使用的是客户端路由,它依赖于 JavaScript 在浏览器端动态渲染页面。当你访问 http://localhost:8080/ 时,浏览器会加载你的应用的 index.html,然后 React Router 根据当前的 URL 动态渲染对应的组件(例如 MyDay 组件)。在这种情况下,Nginx 只需要正确返回 index.html,React Router 就会接管路由。 - 直接访问子路由(如 /cat)时的行为
当你直接访问 http://localhost:8080/cat 时,浏览器会向 Nginx 发送一个请求,试图获取 /cat 对应的资源。然而,Nginx 并不知道 /cat 是一个客户端路由,它会尝试在文件系统中寻找 /cat 对应的静态文件(例如 /cat/index.html)。由于你的 React 项目是单页应用(SPA),并没有 /cat 这样的静态文件,因此 Nginx 返回了 404 错误。 - 为什么访问根路径 / 没有问题?
当你访问 http://localhost:8080/ 时,Nginx 会正确返回 index.html,然后 React Router 在浏览器端接管路由,并根据路由配置渲染正确的页面。
你的问题是由于 React Router 和 Nginx 的路由处理方式不匹配导致的。下面我会详细解释问题的原因,并提供解决方案。
解决方案
为了解决这个问题,你需要在 Nginx 的配置中确保所有未知的路由请求(例如 /cat)都返回 index.html,从而让 React Router 在浏览器端接管路由。以下是详细的解决方案:
方案 1:在 Nginx 中配置路由重定向
你需要修改 Nginx 的配置文件,添加一个规则,确保所有未匹配的路径都返回 index.html。假设你的 React 项目构建后的文件存放在 /usr/share/nginx/html 目录下(或者你自己的部署目录),可以按以下方式配置:
- 打开 Nginx 配置文件(通常位于
/etc/nginx/nginx.conf或/etc/nginx/conf.d/目录下)。 - 添加或修改
server配置块如下:
server 块位于http块内部
# 主要的配置都在server块中
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html; # 替换为你的 React 项目构建文件的实际路径
index index.html;
location / {
try_files $uri $uri/ /index.html; # 核心配置
}
}
解释:
try_files $uri $uri/ /index.html;是关键配置。它的意思是:- 首先尝试查找请求的
$uri(例如/cat)。 - 如果找不到,则尝试查找
$uri/(例如/cat/)。 - 如果仍然找不到,则将请求重定向到
/index.html,由 React Router 接管路由。
- 首先尝试查找请求的
保存配置文件后,重新加载 Nginx 配置以应用更改:
sudo nginx -t # 检查配置文件语法是否正确
sudo systemctl reload nginx # 重新加载 Nginx
配置静态资源和禁止缓存
# 可选:显式配置静态资源(如 build/static/)的 location,有时有助于解决缓存或特定路径问题
location /static/ {
alias dist/static/; # 注意结尾的 /
# 可以设置更长的缓存时间
expires max;
access_log off;
}
# 禁止缓存 index.html,确保更新生效
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
现在直接访问 http://localhost:8080/cat 应该可以正常加载页面。
注意:访问时需要带上baseUrl和蓝绿部署路径,比如:http://localhost:8080/v2/base/cat
方案 2:使用 HashRouter 替代 BrowserRouter
如果你无法修改 Nginx 配置(例如在某些托管环境中),可以考虑在 React 项目中使用 HashRouter 替代 BrowserRouter。HashRouter 使用 URL 的哈希部分(例如 http://localhost:8080/#/cat)来管理路由,这种方式不需要服务器端的支持。
-
修改你的 React 代码,将
BrowserRouter替换为HashRouter: -
重新打包部署你的项目。
优点:
- 不需要修改服务器配置,适合无法控制服务器环境的情况。
缺点:
- URL 中会多出一个
#符号(例如http://localhost:8080/#/cat),可能不符合 SEO 要求或美观需求。
方案 3:使用其他服务器配置(如果不使用 Nginx)
如果你使用的不是 Nginx,而是其他服务器(如 Apache 或 Express),也需要类似的配置:
-
Apache 配置:
在.htaccess文件中添加以下内容:apache 体验AI代码助手 代码解读复制代码RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] -
Express.js 配置:
如果使用 Node.js 的 Express 服务器,确保所有未匹配的路由都返回index.html:javascript 体验AI代码助手 代码解读复制代码const express = require('express'); const path = require('path'); const app = express(); app.use(express.static(path.join(__dirname, 'build'))); app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'build', 'index.html')); }); app.listen(8080);
推荐方案
- 如果你有权限修改服务器配置,推荐使用 方案 1(Nginx 配置),因为这是最常见且最优雅的解决方案,适用于绝大多数单页应用(SPA)。
- 如果你无法修改服务器配置,或者只是临时测试,推荐使用 方案 2(HashRouter)。
测试验证
-
部署完成后,尝试以下操作:
- 直接访问
http://localhost:8080/,验证是否正常跳转到/cat。 - 直接访问
http://localhost:8080/cat,验证是否能正确加载页面。 - 直接访问
http://localhost:8080/dog,验证是否能正确加载页面。
- 直接访问
-
如果仍有问题,可以检查以下几点:
-
确认 Nginx 配置是否正确应用(可以用
nginx -T查看当前生效的配置)。 -
确认 React 项目的构建文件是否正确部署到 Nginx 的
root目录下。 -
查看浏览器开发者工具中的网络请求,确认是否返回了 404 或其他错误。
-