Vue 3 项目上线后,前端资源托管和后端接口转发通常需要同一个入口处理。Nginx 作为反向代理和静态服务器,能够在同一套配置里完成这两件事。如果对路由回退和接口代理的细节不够重视,很容易出现刷新 404、接口 502 或者缓存更新不及时的情况。下面把常用配置拆开说明,并给出一份可以直接调整使用的完整模板。

静态资源托管与 History 路由回退
Vue 3 项目执行 npm run build 后会生成 dist 目录,里面包含 index.html 以及 assets 目录下的带哈希文件名资源。将 Nginx 的 root 指向这个 dist 目录即可提供静态文件访问。但使用 Vue Router 的 history 模式时,用户直接访问例如 /user/profile 这样的深层链接,Nginx 会尝试在服务器磁盘上查找对应路径的文件,找不到就返回 404。开发环境中 Vite 会处理这种回退,生产环境则需要 Nginx 来完成。
解决方式是在 location / 中使用 try_files 指令。它会按照参数顺序依次检查文件是否存在,最后回退到指定文件。典型配置为 try_files $uri $uri/ /index.html;,含义是先查找请求路径对应的物理文件,再查找对应目录,如果都不存在就把请求交给 index.html。这样 Vue Router 可以在浏览器端接管路径并渲染对应组件,刷新页面也不会丢失路由状态。不过要注意,如果某些静态资源路径写错或文件确实缺失,也会回退到 index.html,浏览器可能拿到 200 状态的 HTML 而不是预期的 JS 或 CSS,所以通常需要对静态资源目录单独设置强缓存和精确匹配,减少这种影响。
server {
listen 80;
server_name ipipp.com;
root /var/www/vue-app/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /assets/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}反向代理 API 与路径重写
前后端分离项目中,浏览器直接访问后端接口会触发跨域限制。开发时 Vite 的 server.proxy 可以代理请求,但生产环境需要由 Nginx 承担同样的角色。通过把 /api 路径的请求转发到后端服务,浏览器始终只与 Nginx 同源通信,避免了 CORS 配置的复杂度,也能统一日志和访问入口。
proxy_pass 有一个容易混淆的细节:末尾是否带斜杠会改变转发路径。如果配置为 proxy_pass http://127.0.0.1:3000;,请求 /api/user 会被原样转发为 /api/user;如果写成 proxy_pass http://127.0.0.1:3000/;,则 /api/user 会转发为 /user,相当于去掉了 /api 前缀。这是因为 proxy_pass 中包含 URI 部分时,会用该 URI 替换 location 匹配的部分。实际使用中要根据后端路由是否带有统一前缀来决定,很多后端框架不识别 /api,此时使用带斜杠的写法即可自动去除前缀。
如果后端包含 WebSocket 实时通信,代理还需要升级协议头。默认 Nginx 的 proxy_http_version 为 1.0,会把 Connection 头处理掉,导致 WebSocket 握手失败。需要显式设置 HTTP 1.1,并传递 Upgrade 和 Connection 头。同时调整读超时时间,避免长连接被提前断开。
location /api/ {
proxy_pass http://127.0.0.1:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
}缓存、压缩与安全加固
Vue 3 构建产物中的 JS 和 CSS 文件名包含内容哈希,只要文件内容不变,哈希就不变,因此可以安全地使用长期强缓存。对 /assets/ 目录设置 expires 30d 或 Cache-Control: public, immutable,浏览器会从本地缓存加载,减少重复请求。但 index.html 必须使用短缓存或 no-cache,否则发布新版本后,用户浏览器可能继续使用旧的 HTML,引用已经被删除的旧哈希资源。一般做法是给 index.html 设置 Cache-Control: no-cache,每次请求都向服务器验证是否有更新。
开启 gzip 压缩能显著减小传输体积,尤其对 Vue 打包后的 JavaScript 文件,压缩率经常超过 60%。配置 gzip on 后,通过 gzip_types 指定需要压缩的 MIME 类型,通常包含 application/javascript、text/css、application/json 等。还可以使用 gzip_static on 让 Nginx 直接读取预先生成的 .gz 文件,减少服务器动态压缩的 CPU 开销,前提是构建流程已经生成了对应压缩文件。
安全层面建议隐藏 Nginx 版本号,添加基础安全响应头,并对不常用的请求方法进行限制。例如设置 server_tokens off; 避免暴露版本信息;增加 X-Content-Type-Options: nosniff 防止浏览器 MIME 嗅探;X-Frame-Options: SAMEORIGIN 降低点击劫持风险。这些配置虽然与 Vue 应用本身无关,但能有效提升整体部署的安全性。
server_tokens off;
gzip on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_types application/javascript text/css application/json image/svg+xml;
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location = /index.html {
add_header Cache-Control "no-cache";
}
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header Referrer-Policy strict-origin-when-cross-origin;完整配置示例与常见问题排查
把静态托管、History 回退、API 代理、缓存与安全配置整合到一起,就可以得到一个生产可用的基础模板。上线前需要根据实际域名、后端监听地址、证书路径等信息进行调整。如果使用 HTTPS,可以在 listen 443 ssl; 后配置证书文件路径,并在 80 端口做重定向到 443。下面是一个完整的 server 块,供直接修改使用。
server {
listen 80;
server_name ipipp.com;
root /var/www/vue-app/dist;
index index.html;
server_tokens off;
gzip on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_types application/javascript text/css application/json image/svg+xml;
location / {
try_files $uri $uri/ /index.html;
}
location /assets/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location = /index.html {
add_header Cache-Control "no-cache";
}
location /api/ {
proxy_pass http://127.0.0.1:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
}
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header Referrer-Policy strict-origin-when-cross-origin;
}实际部署中如果遇到刷新 404,先确认 try_files 是否配置在 location / 中,以及是否被其他 location 覆盖。接口 502 一般说明 Nginx 无法连接后端,可以检查后端服务是否正常监听在 127.0.0.1:3000,或者查看 Nginx 的 error log 获取连接错误信息。路径不对时可以用 curl -v http://your-domain/api/xxx 观察实际返回和响应头,再对比后端期望的路径。缓存造成的更新问题通常表现为发布后页面还是旧内容,此时清掉浏览器缓存或强制刷新可以验证,如果仍有问题就需要检查 index.html 的缓存策略是否设置为 no-cache,以及静态资源是否正确生成了新的哈希文件名。
正确配置 Nginx 以后,Vue 3 应用的前端资源和后端 API 可以共享同一个域名和端口,简化了环境管理,也让生产部署更接近标准实践。后续如果需要上 CDN 或负载均衡,这套配置也能作为基础继续扩展。