这是一个非常经典的问题。我来系统地讲解如何让 Nginx 配置与前端打包的 dist 目录结构完美配合。

文章目录
-
- 一、理解前端打包后的路径结构
-
- [1. 相对路径 vs 绝对路径](#1. 相对路径 vs 绝对路径)
- [2. 打包后的典型结构](#2. 打包后的典型结构)
- [二、Nginx 配置模板(三种场景)](#二、Nginx 配置模板(三种场景))
-
- 场景1:根路径部署(最常用)
- [场景2:子路径部署(如你的 `/ring` 情况)](#场景2:子路径部署(如你的
/ring情况)) - 场景3:多环境部署(开发/生产)
- 三、前端打包配置(保持一致性)
-
- [Vite 配置](#Vite 配置)
- React (Create React App)
- [Vue CLI](#Vue CLI)
- 四、完整解决方案模板
-
- [针对你的 `/ring` 问题的完整配置](#针对你的
/ring问题的完整配置)
- [针对你的 `/ring` 问题的完整配置](#针对你的
- 五、部署检查清单
-
- [1. 确认路径一致性](#1. 确认路径一致性)
- [2. 统一前端构建和部署流程](#2. 统一前端构建和部署流程)
- 六、调试技巧
- 七、最佳实践总结
一、理解前端打包后的路径结构
1. 相对路径 vs 绝对路径
前端构建配置决定了资源引用方式:
javascript
// vite.config.js / vue.config.js
export default {
base: '/', // 绝对路径:/assets/style.css
base: './', // 相对路径:./assets/style.css
base: '/ring/', // 子路径:/ring/assets/style.css
}
2. 打包后的典型结构
情况A:根路径部署
dist/
├── index.html
├── assets/
│ ├── style-4SYu6XAP.css
│ └── app-3j7k9Lm.js
└── favicon.ico
情况B:子路径部署
dist/
├── ring/
│ ├── index.html
│ └── assets/
│ ├── style-4SYu6XAP.css
│ └── app-3j7k9Lm.js
二、Nginx 配置模板(三种场景)
场景1:根路径部署(最常用)
nginx
server {
listen 80;
server_name example.com;
# 直接指向 dist 目录
root /var/www/frontend/dist;
index index.html;
# 核心:解决刷新白屏和路由跳转
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源缓存(可选)
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
场景2:子路径部署(如你的 /ring 情况)
nginx
server {
listen 80;
server_name example.com;
root /var/www/frontend;
# 方案A:使用 alias(推荐)
location /ring {
alias /var/www/frontend/ring/dist;
index index.html;
try_files $uri $uri/ /ring/index.html;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# 方案B:使用 root(目录结构必须包含 /ring)
location /ring {
root /var/www/frontend; # 实际路径:/var/www/frontend/ring/dist
index index.html;
try_files $uri $uri/ /ring/index.html;
}
}
场景3:多环境部署(开发/生产)
nginx
# 生产环境
location / {
root /var/www/production/dist;
try_files $uri $uri/ /index.html;
}
# 测试环境
location /beta {
alias /var/www/beta/dist;
try_files $uri $uri/ /beta/index.html;
}
三、前端打包配置(保持一致性)
Vite 配置
javascript
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
// 根据部署路径设置 base
base: process.env.NODE_ENV === 'production'
? '/ring/' // 部署在 /ring/ 路径
: '/', // 部署在根路径
build: {
outDir: 'dist',
assetsDir: 'assets',
// 确保资源路径正确
rollupOptions: {
output: {
entryFileNames: 'assets/[name]-[hash].js',
chunkFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]'
}
}
}
})
React (Create React App)
javascript
// package.json
{
"homepage": "/ring/" // 子路径部署
// "homepage": "." // 相对路径部署
}
Vue CLI
javascript
// vue.config.js
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/ring/'
: '/',
outputDir: 'dist',
assetsDir: 'assets'
}
四、完整解决方案模板
针对你的 /ring 问题的完整配置
nginx
# /etc/nginx/sites-available/dtmusic
server {
listen 443 ssl http2;
server_name dtmusic.bjdtdh.net;
ssl_certificate /etc/nginx/ssl/_.bjdtdh.net.pem;
ssl_certificate_key /etc/nginx/ssl/_.bjdtdh.net.key;
# 主要前端应用
location / {
root /dtdh/www/front/mobileactive;
index index.html;
try_files $uri $uri/ /index.html;
}
# ring 子应用
location /ring {
alias /work/front/aimusic;
index index.html;
# 关键:解决刷新白屏
try_files $uri $uri/ /ring/index.html;
# 或者使用更精确的写法
# try_files $uri $uri/ @ring_fallback;
# location @ring_fallback {
# rewrite ^/ring/(.*)$ /ring/index.html?$args last;
# }
}
# API 代理
location /admin-api/ {
proxy_pass http://127.0.0.1:48079/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 静态资源缓存(可选优化)
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
# 对于 /ring 下的静态资源
try_files $uri =404;
}
}
五、部署检查清单
1. 确认路径一致性
bash
# 创建检查脚本
cat > check_deploy.sh << 'EOF'
#!/bin/bash
echo "=== 检查前端部署 ==="
# 检查 dist 目录结构
echo "1. Dist 目录结构:"
ls -la /work/front/aimusic/
echo -e "\n2. 检查关键文件:"
test -f /work/front/aimusic/index.html && echo "✓ index.html 存在" || echo "✗ index.html 不存在"
test -f /work/front/aimusic/assets/style-4SYu6XAP.css && echo "✓ CSS 存在" || echo "✗ CSS 不存在"
echo -e "\n3. 检查文件权限:"
ls -la /work/front/aimusic/index.html
echo -e "\n4. 测试访问:"
curl -I https://dtmusic.bjdtdh.net/ring/ 2>/dev/null | head -1
curl -I https://dtmusic.bjdtdh.net/ring/assets/style-4SYu6XAP.css 2>/dev/null | head -1
EOF
chmod +x check_deploy.sh
./check_deploy.sh
2. 统一前端构建和部署流程
bash
# deploy.sh - 自动化部署脚本
#!/bin/bash
# 1. 前端构建
cd /path/to/frontend-project
npm run build
# 2. 验证构建产物
if [ ! -f "dist/index.html" ]; then
echo "构建失败:index.html 不存在"
exit 1
fi
# 3. 备份当前版本
mv /work/front/aimusic /work/front/aimusic.bak
# 4. 部署新版本
cp -r dist /work/front/aimusic
# 5. 设置权限
chown -R www-data:www-data /work/front/aimusic
chmod -R 755 /work/front/aimusic
# 6. 测试 Nginx 配置
nginx -t && nginx -s reload
echo "部署完成!"
六、调试技巧
快速定位路径问题
nginx
# 添加调试 location
location = /debug-path {
add_header Content-Type text/plain;
return 200 "Document Root: $document_root\nURI: $uri\nFilename: $document_root$uri\n";
}
location = /ring/debug-path {
alias /work/front/aimusic;
add_header Content-Type text/plain;
return 200 "Alias Path: /work/front/aimusic\nURI: $uri\n";
}
访问 https://dtmusic.bjdtdh.net/debug-path 查看实际路径。
实时监控
bash
# 监控访问日志,查看具体哪个文件404
tail -f /var/log/nginx/access.log | grep " 404 "
# 监控错误日志
tail -f /var/log/nginx/error.log
七、最佳实践总结
- 前端配置 :明确
base/publicPath与部署路径一致 - Nginx 配置 :使用
try_files $uri $uri/ /index.html解决 SPA 路由 - 子路径部署 :优先使用
alias,配合正确的try_files - 路径验证:部署后立即测试静态资源可访问性
- 版本管理:保留旧版本备份,快速回滚
针对你的问题,立即执行:
bash
# 1. 找到实际文件位置
find /work/front -name "style-4SYu6XAP.css" 2>/dev/null
# 2. 根据输出结果,按上面的场景2调整配置
# 3. nginx -t && nginx -s reload