Qiankun 微应用部署 Nginx 配置问题

27 阅读4分钟

🐛 问题表现

浏览器错误:

javascript
GET http://xx.xxx.xxx.xx/keyboard/keyboard-management.ef48a688dd95df4ddd57.js 404
Uncaught SyntaxError: Unexpected token '<'

🔍 问题排查过程

问题 1: 微应用 JS 文件 404

症状:

  • 主应用正常加载
  • 点击微应用菜单,JS 文件找不到
  • 错误日志显示在 /data/apps/frontend/main/keyboard/ 下找文件

根本原因:

nginx
# ❌ 错误配置
location ~* .(js|css|png|...)$ {
    root /data/apps/frontend/main;  # 所有静态资源都去主应用目录找
}

location /keyboard/ {
    alias /data/apps/frontend/keyboard/;  # 这个规则永远不会生效
}

Nginx Location 匹配优先级:

  • 正则匹配 ~* 优先级 > 普通前缀匹配
  • 请求 /keyboard/xxx.js 被正则规则拦截
  • 使用 root /data/apps/frontend/main → 404

解决方法:

nginx
# ✅ 使用 ^~ 提高优先级
location ^~ /keyboard/ {
    alias /data/apps/frontend/keyboard/;
}

问题 2: JS 文件返回 HTML 内容

症状:

bash
GET http://xx.xxx.xxx.xx/keyboard/keyboard-management.js 200 OK
Uncaught SyntaxError: Unexpected token '<'  # JS 文件内容是 HTML

根本原因:

nginx
# ❌ 错误配置
location ^~ /keyboard/ {
    alias /data/apps/frontend/keyboard/;
    try_files $uri $uri/ /keyboard/index.html;  # 找不到文件就返回 HTML
}

请求流程:

  1. 请求:/keyboard/xxx.js
  2. 文件不存在(路径映射错误)
  3. try_files fallback 到 index.html
  4. 浏览器收到 HTML 内容,解析失败

问题 3: Nginx Alias 路径映射错误

症状:

bash
curl -I http://localhost/keyboard/keyboard-management.js
# 返回:301 Moved Permanently
# Location: http://localhost/keyboard/keyboard-management.js/

根本原因:

nginx
# ❌ Nginx 把 JS 文件当成目录处理
location ~ ^/keyboard/.*.(js|css)$ {
    alias /data/apps/frontend/keyboard/;  # 正则匹配 + alias 无法正确替换路径
}

Nginx Alias 指令问题:

  • alias 指令会完全替换 location 匹配的路径
  • 在正则匹配中使用 alias 容易出现路径映射错误
  • Nginx 无法正确处理尾部斜杠,导致 301 重定向

✅ 最终解决方案

方案对比

表格

方案配置方式优点缺点
方案 1调整目录结构 + root配置清晰,路径匹配准确需要修改目录结构
方案 2精确的 alias 配置不改变目录配置复杂,容易出错
方案 3简化配置 + 去掉 fallback最简单,最稳定无 SPA fallback(但微应用不需要)

最终采用方案 3(最简配置)

nginx
server {
    listen 80 default_server;
    server_name _;
    
    # ✅ Keyboard 微应用(使用 ^~ 提高优先级)
    location /keyboard/ {
        alias /data/apps/frontend/keyboard/;
        # ✅ 不使用 try_files,直接返回文件
        add_header Access-Control-Allow-Origin * always;
    }
    
    # ✅ Mouse 微应用
    location /mouse/ {
        alias /data/apps/frontend/mouse/;
        add_header Access-Control-Allow-Origin * always;
    }
    
    # API 代理
    location /api/ {
        proxy_pass http://127.0.0.1:8080/;
    }
    
    # ✅ 主应用(最低优先级)
    location / {
        root /data/apps/frontend/main;
        try_files $uri $uri/ /index.html;  # 只有主应用需要 SPA fallback
    }
}

📚 关键知识点

1. Nginx Location 匹配优先级

nginx
# 优先级从高到低:
location = /exact/path     # 1️⃣ 精确匹配
location ^~ /prefix/       # 2️⃣ 前缀匹配(不检查正则)
location ~ /regex/         # 3️⃣ 正则匹配(区分大小写)
location ~* /regex/        # 4️⃣ 正则匹配(不区分大小写)
location /prefix/          # 5️⃣ 普通前缀匹配

2. Root vs Alias

nginx
# root:拼接路径
location /static/ {
    root /data/www;
    # /static/file.js → /data/www/static/file.js
}

# alias:替换路径
location /static/ {
    alias /data/files/;
    # /static/file.js → /data/files/file.js
}

⚠️ Alias 注意事项:

  • location 和 alias 的尾部斜杠必须一致
  • 正则匹配 + alias 容易出问题
  • 尽量避免在复杂场景使用 alias

3. Try_files 指令

nginx
# 语法
try_files $uri $uri/ /fallback.html;

# 工作流程
# 1. 尝试访问 $uri(文件)
# 2. 尝试访问 $uri/(目录)
# 3. 返回 /fallback.html

⚠️ 微应用注意:

  • 微应用的静态资源(JS/CSS/图片)不应该 fallback 到 HTML
  • 只有 HTML 页面路由需要 fallback
  • 否则会出现"请求 JS 返回 HTML"的问题

🎯 Qiankun 微应用 Nginx 配置最佳实践

✅ 推荐配置模板

nginx
server {
    listen 80;
    server_name your-domain.com;
    
    # 1️⃣ 微应用路由(使用 ^~ 提高优先级)
    location ^~ /micro-app1/ {
        alias /path/to/micro-app1/;
        index index.html;
        # 不使用 try_files,让 Nginx 直接返回文件或 404
        add_header Access-Control-Allow-Origin * always;
    }
    
    location ^~ /micro-app2/ {
        alias /path/to/micro-app2/;
        index index.html;
        add_header Access-Control-Allow-Origin * always;
    }
    
    # 2️⃣ API 代理
    location ^~ /api/ {
        proxy_pass http://backend:8080/;
    }
    
    # 3️⃣ 主应用(最低优先级,使用 SPA fallback)
    location / {
        root /path/to/main-app;
        try_files $uri $uri/ /index.html;
        add_header Access-Control-Allow-Origin * always;
    }
}

✅ 关键要点

  1. 微应用路由必须使用 ^~

    • 确保优先级高于其他规则
    • 避免被正则规则拦截
  2. 微应用不使用 try_files

    • 静态资源直接返回,不 fallback
    • 避免返回 HTML 导致 JS 解析错误
  3. CORS 头必须设置

    • qiankun 需要跨域加载微应用资源
    • add_header Access-Control-Allow-Origin * always;
  4. 路由顺序很重要

    • 微应用路由放在前面
    • 主应用路由放在最后
    • API 代理放中间
  5. 目录结构建议

    bash
    /data/apps/frontend/
    ├── main/          # 主应用
    ├── keyboard/      # 微应用 1
    └── mouse/         # 微应用 2
    

🔧 调试技巧

1. 检查 Nginx 路由匹配

bash
# 查看访问日志
tail -f /var/log/nginx/access.log

# 查看错误日志
tail -f /var/log/nginx/error.log

# 测试文件是否存在
curl -I http://localhost/keyboard/xxx.js

# 查看返回内容
curl http://localhost/keyboard/xxx.js | head -c 100

2. 验证路径映射

bash
# 检查实际文件
ls -la /data/apps/frontend/keyboard/

# 测试 Nginx 配置
nginx -t

# 重新加载配置
systemctl reload nginx

3. 浏览器调试

javascript
// F12 → Network 面板
// 查看请求的 Response Headers:
// Content-Type: application/javascript  ✅ 正确
// Content-Type: text/html               ❌ 错误

📊 总结

表格

问题阶段原因解决方法
404 错误Location 匹配优先级错误使用 ^~ 提高微应用路由优先级
返回 HTMLtry_files 错误 fallback移除微应用的 try_files 指令
301 重定向Alias + 正则匹配路径错误简化配置,避免复杂的正则匹配

核心原则:

  • 微应用路由配置要简单直接
  • 优先级要高于其他规则
  • 静态资源要直接返回,不做 fallback

🎉 问题解决!