如何保持nginx配置与前端打包dist的路径保持一致、解决页面刷新白屏以及页面跳转问题

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

文章目录

一、理解前端打包后的路径结构

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

七、最佳实践总结

  1. 前端配置 :明确 base/publicPath 与部署路径一致
  2. Nginx 配置 :使用 try_files $uri $uri/ /index.html 解决 SPA 路由
  3. 子路径部署 :优先使用 alias,配合正确的 try_files
  4. 路径验证:部署后立即测试静态资源可访问性
  5. 版本管理:保留旧版本备份,快速回滚

针对你的问题,立即执行:

bash 复制代码
# 1. 找到实际文件位置
find /work/front -name "style-4SYu6XAP.css" 2>/dev/null

# 2. 根据输出结果,按上面的场景2调整配置
# 3. nginx -t && nginx -s reload
相关推荐
想唱rap1 小时前
五种IO模型和非阻塞IO
linux·运维·服务器·网络·数据库·tcp/ip
环流_1 小时前
nacos:负载均衡 3大核心操作
运维·nacos·负载均衡
阿洛学长2 小时前
CSDN、掘金、简书博客文章如何转为Markdown?
运维·数据库·架构·php·持续部署
方安乐2 小时前
交换机的自学机制
运维·服务器·网络
十有八七2 小时前
AI 开发,本质是一场文档的生命周期管理
前端·人工智能
Hyyy3 小时前
普通前端自救记录——第0周
前端
前端若水3 小时前
在 Vue 2 与 Vue 3 中使用 markdown-it-vue 渲染 Markdown 和数学公式
前端·javascript·vue.js
之歆3 小时前
DAY_10 JavaScript 深度解析:原型链 · 引用类型 · 内置对象 · 数组方法全攻略(下)
开发语言·前端·javascript·ecmascript