微前端路由由JS运行时控制,子应用必须显式接收base path(如window.__MICRO_APP_BASE_ROUTE__),配置Vue Router的createWebHistory或React Router的basename,服务端需兜底子应用路径,否则刷新404;history操作须经沙箱拦截,避免污染全局路由栈。

微前端里没有“HTML结构决定路由”的事——路由隔离和分发完全由 JS 运行时控制,HTML 只是最终渲染容器。硬靠 <div id="app"> 或 index.html 的 DOM 结构去设计路由,90% 会卡在刷新 404、子应用跳转失效、或无限重定向上。
子应用路由必须显式接收 base path,不能猜也不能 fallback
子应用启动时如果把当前 URL /app1/user/123 当作 /user/123 解析,就会漏掉前缀,导致内部路由匹配失败。这不是框架 bug,是配置缺失。
- 主应用挂载前必须通过
window.__MICRO_APP_BASE_ROUTE__ = '/app1'或 props 显式传入 base - Vue Router 必须写
createRouter({ history: createWebHistory(window.__MICRO_APP_BASE_ROUTE__ || '/'), ... }) - React Router v6+ 必须用
<Router basename={base}>包裹,不能依赖process.env.PUBLIC_URL或构建时硬编码 - 子应用的
useNavigate('/list')实际会跳到/app1/list,不是/list;否则 history.pushState 写错位置,主应用收不到变更通知
服务端必须兜底所有子应用路径,否则刷新必 404
用户直接访问 https://host/app1/order/5,Nginx 或 Express 收到请求后根本不会进前端路由逻辑,而是按静态路径查找文件,自然返回 404。
- Nginx 配置要覆盖整个子应用路径:
location /app1 { try_files $uri $uri/ /app1/index.html; } - Express 示例:
app.get('/app1/*', (req, res) => res.sendFile(path.join(__dirname, 'index.html'))); - 注意:这个兜底只针对 HTML 入口;JS/CSS 等资源仍走正常静态服务,不在此规则内
- 如果子应用部署在子域名(如
app1.example.com),则无需服务端兜底,但需确保主应用能跨域加载其 entry 脚本
history 操作必须被沙箱拦截,否则子应用会污染全局路由栈
子应用调用 history.pushState() 或 router.push() 时,若未被运行时沙箱拦截,会直接修改顶层 window.history,导致主应用无法感知、后退按钮错乱、甚至触发错误重定向。
立即学习“前端免费学习笔记(深入)”;
- qiankun 等主流框架默认启用 history 沙箱,但需确认子应用未禁用:
sandbox: { strictStyleIsolation: true, experimentalStyleIsolation: false }不影响 history - 自研沙箱必须重写
history.pushState、replaceState和popstate事件监听,绑定到子应用专属的虚拟 history 实例 - 子应用不能直接访问
window.history—— 所有路由操作应走框架提供的triggerAppUpdate或setLocation接口 - 未拦截时典型现象:点击子应用菜单,URL 变了但主应用没切换;或后退一次跳回主应用首页而非子应用上一页
真正难的不是写对一个 basename,而是让子应用彻底放弃“自己管路由”的惯性思维——它得接受自己只是主应用路由状态的一个视图,所有跳转、刷新、前进后退,都必须经由宿主协调。这点一旦没对齐,后续样式隔离、通信、生命周期全都会连锁出问题。



















