在前端开发工作中,npm run build 命令生成的 dist 目录常常被视为开发的终点。然而,如何将这个 dist 目录高效、稳定地交付给浏览器,却是另一项关键技能。这通常不是 Node.js 的任务(SSR 除外),而是 Nginx 的舞台。
一个常见的面试问题是:“Vue/React 单页应用上线后,为什么刷新页面会报 404?如何解决?” 如果你的回答停留在“运维负责配置”,可能会错过展现你技术深度的机会。若能清晰阐述并手写 try_files 指令,则能体现你具备理解全链路原理的思维。
本文将聚焦于前端开发者必须掌握的 Nginx 核心配置,不涉及复杂的负载均衡,只解决最迫切的部署问题。
01. 核心救星:解决 SPA 刷新 404 问题
这是前端单页应用部署时遇到的第一道坎。
现象:应用首页可以正常访问,但当你跳转到 /user/profile 这类子路由后,点击浏览器的刷新按钮,页面会变成空白,并显示 404 Not Found 错误。
原理剖析:
Nginx 默认的行为是基于文件系统来寻找资源。当你请求 domain.com/user/profile 时,Nginx 会去配置的根目录下寻找名为 user/profile 的实体文件或文件夹。显然,这个路径在前端构建产物中并不存在,因为这是前端路由(通常是 History 模式)管理的虚拟路径,其实际内容仍然包含在 index.html 文件之中。
解决方案:try_files 指令
我们需要告诉 Nginx:“如果在文件系统中找不到对应的文件或目录,就将请求回退给 index.html,由前端路由框架自己来处理这个路径。”
关键配置如下:
server {
listen 80;
server_name my-app.com;
root /usr/share/nginx/html; # 此处指向你的 dist 目录
location / {
index index.html;
# 🌟 核心配置:尝试寻找请求的文件,若失败则返回 index.html
try_files $uri $uri/ /index.html;
}
}
02. 跨域终结者:配置反向代理 (Reverse Proxy)
痛点场景:前端应用部署在 my-app.com 域名下,而后端 API 服务位于 api.server.com。前端直接请求后端接口会因浏览器的同源策略而触发 CORS 跨域错误。
虽然后端可以通过配置 CORS 响应头来解决,但更优雅、安全的做法是利用 反向代理 让前端感觉所有资源都来自同一个源。
解决方案:proxy_pass 指令
我们让前端请求 my-app.com/api/xxx,然后由 Nginx 在服务器端透明地将请求转发到真实的后端地址。
location /api/ {
# 1. 指定转发的目标后端地址
proxy_pass http://api.server.com/;
# 2. 可选:重写请求路径(根据后端接口是否需要 /api 前缀决定)
# 如果后端接口本身没有 /api 前缀,则需要去掉它
# rewrite ^/api/(.*)$ /$1 break;
# 3. 传递必要的请求头,确保后端能获取真实客户端信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
技术讨论要点:在生产环境中,使用 Nginx 反向代理解决跨域问题,通常比让后端直接开放 CORS 更安全。这种方式可以隐藏后端服务的真实内网拓扑结构,并统一进行请求管理。
03. 性能加速:开启 Gzip / Brotli 压缩
效果对比:构建产物中一个 1MB 的 vendor.js 文件,用户加载可能需要数秒。若开启 Gzip 压缩,其体积可能瞬间降至 300KB 左右,大幅提升加载速度。
Nginx 默认可能未开启 Gzip 压缩,或仅压缩 HTML 文件。我们需要手动配置以支持对 JS、CSS 等静态资源的压缩。
# 在 http 或 server 区块中配置
# 开启 Gzip 压缩
gzip on;
# 只对大于 1KB 的文件进行压缩(太小的文件压缩后体积可能反而变大)
gzip_min_length 1k;
# 压缩级别 1-9,推荐设为 5 或 6(在压缩率和 CPU 消耗间取得平衡)
gzip_comp_level 6;
# 🌟 关键:指定需要压缩的 MIME 类型
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
# 启用 Vary: Accept-Encoding 响应头,利于缓存
gzip_vary on;
进阶选项:Brotli
Brotli (br) 是一种比 Gzip 更新、压缩率更高的算法(通常能再提升 15-20% 的压缩率)。如果你的 Nginx 已编译了 Brotli 模块,可以同时配置 brotli on; 以获得更佳性能。
04. 缓存策略:精细化控制浏览器缓存
合理的缓存策略能极大提升重复访问的体验。基本原则如下:
- HTML 文件 (
index.html):不应设置长期缓存(或缓存时间极短)。否则应用发布新版本后,用户可能因缓存而继续访问旧页面。
- JS、CSS、图片等静态资源:应设置长期强缓存。因为现代构建工具(如 Webpack、Vite)会为文件内容生成哈希值并体现在文件名中(如
app.a1b2c3d.js)。只要文件内容不变,文件名就不变,缓存安全;文件内容变化,文件名也随之改变,相当于一个新的资源 URL,可自然触发更新。
Nginx 配置示例:
# 1. 针对根路径,主要处理 HTML 及路由回退,并禁用缓存
location / {
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# 2. 匹配静态资源,设置 1 年长期缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
05. 常见避坑:解决大文件上传报错 413
如果你的应用包含文件上传功能,特别是支持大文件上传时,必须注意 Nginx 的默认限制。
Nginx 默认限制客户端请求体最大为 1MB。一旦上传的文件超过此大小,服务器会直接返回 413 Request Entity Too Large 错误。
解决方案非常简单,在 server 或 http 区块中调整这个限制即可:
server {
# 将客户端最大请求体大小调整为 100MB,可根据需要修改
client_max_body_size 100m;
}
总结
Nginx 是现代前端应用在生产环境中的“守护者”,它熟练地处理了路由回退、跨域代理、资源压缩、缓存策略乃至安全防护等关键任务。掌握这些核心配置,意味着你能够独立完成应用上线的最后一步,实现快速、稳定的部署。
将这些配置片段妥善保存到你的知识库中,下次项目部署时,你将能从容应对。想要探索更多关于系统设计、网络协议或DevOps的深度内容,欢迎访问云栈社区,与更多开发者交流学习。