为什么微应用不需要配置 try_files?

80 阅读6分钟

📚 核心概念:SPA 路由模式

1. 传统 SPA 应用的路由流程

css
用户访问 → Nginx → HTML → 前端路由

示例:独立运行的 React 应用

nginx
# 主应用(独立 SPA)
location / {
    root /data/apps/frontend/main;
    try_files $uri $uri/ /index.html;  # ✅ 需要 try_files
}

为什么需要 try_files

bash
# 用户直接访问深层路由
https://example.com/users/profile

# Nginx 处理流程:
1. 查找文件:/data/apps/frontend/main/users/profile → ❌ 不存在
2. 查找目录:/data/apps/frontend/main/users/profile/ → ❌ 不存在
3. Fallback:返回 /index.html → ✅ 让前端路由接管

# 浏览器接收到 index.html
# React Router 解析 URL:/users/profile
# 渲染对应组件

没有 try_files 会发生什么?

bash
# 用户访问:https://example.com/users/profile
# Nginx:文件不存在 → 404 错误 ❌
# 前端路由永远不会执行

🎯 Qiankun 微前端架构的不同之处

2. Qiankun 的路由职责划分

scss
主应用              微应用
  ↓                  ↓
前端路由           静态资源
控制页面          (JS/CSS/图片)

关键区别:

  • ✅ 主应用:负责所有路由控制(包括微应用路由)
  • ✅ 微应用:只提供静态资源(JS Bundle)
  • ❌ 微应用:不直接处理 URL 路由

3. 实际请求流程对比

场景 A:主应用路由(需要 try_files)

bash
# 1️⃣ 用户直接访问主应用路由
https://example.com/dashboard

# 2️⃣ Nginx 处理
location / {
    root /data/apps/frontend/main;
    try_files $uri $uri/ /index.html;  # ✅ 必须
}

# 3️⃣ 流程
用户访问 /dashboard
    ↓
Nginx: /dashboard 文件不存在
    ↓
try_files fallback → 返回 /index.html
    ↓
主应用 React Router 解析 /dashboard
    ↓
渲染 Dashboard 页面

场景 B:微应用路由(不需要 try_files)

bash
# 1️⃣ 用户访问微应用路由
https://example.com/keyboard-management

# 2️⃣ 主应用处理(不是 Nginx!)
主应用 index.html 加载
    ↓
主应用 React Router 解析 /keyboard-management
    ↓
Qiankun 决定加载微应用
    ↓
请求微应用资源:
  - /keyboard/keyboard-management.js  ← ✅ 直接请求 JS 文件
  - /keyboard/index.html               ← ❌ 不会请求
    ↓
微应用 JS 执行并挂载

关键点:

  • 🔴 用户永远不会直接访问微应用的 HTML 路由
  • 🟢 所有路由都由主应用控制
  • 🟢 微应用只被当作 JS 库加载

4. 具体代码示例

主应用路由配置(React Router)

javascript
// 主应用 App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        {/* ✅ 主应用路由 */}
        <Route path="/" element={<Home />} />
        <Route path="/dashboard" element={<Dashboard />} />
        
        {/* ✅ 微应用路由(由主应用控制) */}
        <Route path="/keyboard-management/*" element={
          <MicroAppContainer name="keyboard-management" />
        } />
        <Route path="/mouse-management/*" element={
          <MicroAppContainer name="mouse-management" />
        } />
      </Routes>
    </BrowserRouter>
  );
}

// ✅ 微应用容器组件
function MicroAppContainer({ name }) {
  useEffect(() => {
    // Qiankun 加载微应用
    loadMicroApp({
      name,
      entry: `/keyboard/`,  // ← 只请求静态资源
      container: '#micro-app-container',
    });
  }, []);
  
  return <div id="micro-app-container" />;
}

用户访问流程

bash
# 用户输入 URL:https://example.com/keyboard-management
# ↓

# 1️⃣ 浏览器请求
GET https://example.com/keyboard-management
    ↓
# 2️⃣ Nginx 处理(主应用配置)
location / {
    root /data/apps/frontend/main;
    try_files $uri $uri/ /index.html;  # ✅ fallback 到主应用
}
# 返回:/data/apps/frontend/main/index.html# 3️⃣ 主应用加载
<script src="/main.js"></script>  # 主应用 JS# 4️⃣ React Router 解析
URL: /keyboard-management
Route 匹配: <Route path="/keyboard-management/*" ... />
    ↓
# 5️⃣ Qiankun 加载微应用
loadMicroApp({ entry: '/keyboard/' })
    ↓
# 6️⃣ 请求微应用资源(AJAX 请求)
GET /keyboard/index.html        # Qiankun 解析入口
GET /keyboard/keyboard-management.js  # ← 真正的 JS 文件
GET /keyboard/xxx.css
    ↓
# 7️⃣ Nginx 处理微应用资源请求
location /keyboard/ {
    alias /data/apps/frontend/keyboard/;
    # ❌ 不需要 try_files
    # 因为这些都是真实的文件请求,不是路由
}
# 返回:实际的 JS/CSS 文件内容

🔍 详细对比:主应用 vs 微应用

主应用请求模式

表格

请求类型URL 示例Nginx 处理结果
首页/文件存在 → 返回 index.html
路由/dashboard文件不存在 → try_files → index.html
路由/users/123文件不存在 → try_files → index.html
静态资源/main.js文件存在 → 返回 JS

没有 try_files:

bash
用户访问 /dashboard
    ↓
Nginx: 404 Not Found  ❌
前端路由永远不会执行

微应用请求模式

表格

请求类型URL 示例请求发起者Nginx 处理
入口 HTML/keyboard/Qiankun返回 index.html ✅
JS Bundle/keyboard/keyboard-management.jsQiankun返回 JS 文件 ✅
CSS/keyboard/style.cssQiankun返回 CSS 文件 ✅
图片/keyboard/logo.png微应用返回图片 ✅
❌ 路由/keyboard/page1不会发生-

关键:

  • 🔴 用户不会直接访问 /keyboard/page1
  • 🟢 只有主应用控制路由,然后加载微应用资源
  • 🟢 所有请求都是实际的文件路径

💡 实际验证

情况 1:如果微应用配置了 try_files

nginx
# ❌ 错误配置
location /keyboard/ {
    alias /data/apps/frontend/keyboard/;
    try_files $uri $uri/ /keyboard/index.html;  # 会出问题
}

会发生什么?

bash
# Qiankun 请求:/keyboard/keyboard-management.js
# ↓
# Nginx 处理:
1. 尝试文件:/data/apps/frontend/keyboard/keyboard-management.js
   # 如果文件存在 → ✅ 返回 JS(正常)
   # 如果文件不存在(路径错误) → ❌ 继续

2. 尝试目录:/data/apps/frontend/keyboard/keyboard-management.js/
   # 不存在 → 继续

3. Fallback:返回 /keyboard/index.html  # ❌ 问题在这里!
   # 浏览器期望收到 JS,却收到 HTML

# 结果:
Uncaught SyntaxError: Unexpected token '<'
# 因为浏览器把 HTML 当 JavaScript 解析了

情况 2:不配置 try_files(正确)

nginx
# ✅ 正确配置
location /keyboard/ {
    alias /data/apps/frontend/keyboard/;
    # 不配置 try_files
}

会发生什么?

bash
# Qiankun 请求:/keyboard/keyboard-management.js
# ↓
# Nginx 处理:
1. 直接查找文件:/data/apps/frontend/keyboard/keyboard-management.js
   # 如果存在 → ✅ 返回 JS
   # 如果不存在 → ✅ 返回 404

# 结果:
# 文件存在 → 微应用正常加载 ✅
# 文件不存在 → 明确的 404 错误,易于排查 ✅

🎯 特殊情况:微应用内部路由

问题:微应用内部有子路由怎么办?

javascript
// 微应用内部路由
<BrowserRouter basename="/keyboard-management">
  <Routes>
    <Route path="/" element={<List />} />
    <Route path="/create" element={<Create />} />  // 子路由
    <Route path="/edit/:id" element={<Edit />} />  // 子路由
  </Routes>
</BrowserRouter>

答案:依然不需要 Nginx 的 try_files!

原因:

bash
# 1️⃣ 用户访问:https://example.com/keyboard-management/create
# ↓

# 2️⃣ 主应用处理
主应用路由匹配: /keyboard-management/*
    ↓
Qiankun 加载微应用
    ↓
# 3️⃣ 微应用 JS 执行
微应用 React Router 解析: /keyboard-management/create
    ↓
渲染 Create 组件 ✅

# 🔴 注意:整个过程中,浏览器只请求了一次 HTML(主应用的)
# 微应用的子路由完全在前端内存中处理,不涉及 Nginx

📊 总结表格

表格

对比项主应用微应用
路由控制自己控制主应用控制
用户访问方式直接访问 URL不会直接访问
Nginx 职责返回 HTML + 处理路由 fallback只返回静态资源
需要 try_files✅ 是❌ 否
请求类型HTML 页面 + 静态资源只有静态资源
404 情况Fallback 到 index.html真实的 404 错误

✅ 最佳实践总结

1. 主应用 Nginx 配置

nginx
# ✅ 需要 try_files
location / {
    root /data/apps/frontend/main;
    try_files $uri $uri/ /index.html;  # 处理 SPA 路由
}

原因:

  • 用户会直接访问任意路由
  • 需要 fallback 到 index.html 让前端路由接管

2. 微应用 Nginx 配置

nginx
# ✅ 不需要 try_files
location /keyboard/ {
    alias /data/apps/frontend/keyboard/;
    # 直接返回文件,不做 fallback
}

原因:

  • 只提供静态资源服务
  • 所有请求都是真实文件路径
  • 路由由主应用和微应用前端代码控制

3. 记忆口诀

主应用:用户入口,需要路由 fallback → try_files ✅
微应用:资源仓库,直接文件访问 → 不需要 try_files ❌

🔧 调试技巧

如何验证是否需要 try_files?

bash
# 问自己 3 个问题:

1. 用户会直接在浏览器输入这个路径吗?
   - 主应用:会(/dashboard, /users/123)→ 需要
   - 微应用:不会(由 Qiankun 加载)→ 不需要

2. 这个路径是真实文件还是前端路由?
   - 真实文件(/app.js, /logo.png)→ 不需要
   - 前端路由(/dashboard)→ 需要

3. 谁在控制这个路由?
   - 用户(直接访问)→ 需要 Nginx fallback
   - 前端代码(AJAX 加载)→ 不需要 Nginx fallback

希望这个解释清楚了!核心就是:

  • 🎯 微应用在 Qiankun 架构中只是"静态资源包",不是独立的 SPA 应用
  • 🎯 所有路由控制权都在主应用,微应用只负责提供 JS/CSS/图片等文件
  • 🎯 Nginx 对微应用只需要做"文件服务器",不需要处理路由 fallback