☰
qiankun微前端跳转全攻略:主应用与子应用路由导航实践
2026/10/1 16:35:23 网站建设 项目流程

1. 先理清楚:qiankun里到底有哪几类“跳转”

1.1 四类跳转的直观场景

在做微前端改造之前,大部分人遇到的“跳转”就是一个单页应用里路由跳来跳去。但一旦上了qiankun,事情就没那么简单了。你面前会出现四个完全不同的跳转场景:

  • 主应用自己内部的页面跳转(比如主应用的首页跳到主应用的管理中心)
  • 主应用跳到某个微应用(比如主应用菜单点击后,进入订单微应用)
  • 微应用内部自己的页面跳转(这个其实和普通单页应用没区别)
  • 微应用跳到主应用,或者微应用A跳到微应用B

我用一个真实项目举例:有一个后台系统,主应用负责登录、权限、统一布局和导航菜单,子应用有订单中心、用户中心、数据中心三个独立的Vue工程。用户登录后从主应用的仪表盘点“订单管理”,然后进入订单微应用查看详情,再点“该用户的更多信息”直接跳转到用户中心微应用。这一套流程里,主应用跳子应用、子应用跳主应用、子应用互跳全都有涉及。

如果你只会在主应用里用router.push跳微应用,而没处理好子应用之间的互联,后面业务复杂起来会非常痛苦。因为qiankun本身不是一个路由框架,它只管微应用加载和卸载,并不帮你处理“应用之间怎么导航”。所有跨应用的跳转策略,都需要你在启动qiankun之前就设计好。

1.2 跳转之前必须搞懂的路由模式问题

我在处理跳转问题时发现,90%的跳转异常都出在路由模式不统一。qiankun官方文档里,主应用干活用的是history模式,但子应用有的项目为了省事会采用hash模式。这两种模式混用时,跳转的逻辑会不太一样,轻则不按预期工作,重则直接404。

先说结论:如果主应用用的是history模式,子应用最好也统一用history模式。如果主应用是hash模式,你很难用纯history方式去拼接一个能直接访问的URL,比如主应用是hash路由,你直接去微应用里用this.$router.push('/order')是可行的,但你想通过浏览器地址栏拼一个完整地址来打开微应用页面,就有很多坑,后面我会讲到。

再看qiankun的匹配规则。主应用注册微应用时,会配置activeRule,比如/order。那如果你在地址栏输入https://example.com/order/detail/123,qiankun就会判定该加载订单微应用。子应用收到URL后,根据自己内部的Vue Router再解析/detail/123。这里有个非常重要的细节:子应用必须设置base为/order,否则它会把/detail/123当成根路径去匹配,结果出来一个找不到路由的白屏页面。

另外,qiankun在加载微应用时,会给子应用注入一条publicPath,但在某些场景下,比如子应用里用了懒加载组件,切换路由后组件路径会错乱,也会表现为“跳转空白”。看起来是跳转问题,实际上是Webpack打包配置问题。所以排查问题时,先统一路由模式,再检查base配置,最后看构建产物路径。这三件事是跳转的底层前提,一件都不能少。

2. 主应用内部跳转:最容易翻车的历史模式问题

2.1 主应用用Vue Router时怎么跳

如果主应用是一个Vue 2工程,使用Vue Router 3.x的history模式,主应用内部跳转本身没有任何特殊之处,正常写:

// 主应用组件内 this.$router.push('/home') this.$router.push('/about')

但你有没有想过这样一个问题:当主应用当前停留在一个微应用的页面里,URL可能是https://example.com/order/detail/123。这时候你在主应用的某个公共组件(比如顶部全局搜索框)里执行this.$router.push('/home'),会发生什么?

如果你没有在beforeEach守卫里做特殊处理,这个跳转会触发qiankun路由匹配。因为URL从/order/xxx变成了/home,qiankun会判定当前不匹配/order,于是卸载订单微应用,加载主应用的/home页面。这是符合预期的。

但如果你在微应用页面内点击了主应用的一个“返回首页”按钮,而这个按钮用的不是主应用暴露的路由实例,而是直接修改window.location.href = '/home',那就会触发整页刷新。整页刷新在微前端架构下不是不行,但会丢失微应用的内存状态,权限信息如果存在sessionStorage里倒是没事,但如果存在Vuex内存变量里就得重新拉取。所以我后来在主应用菜单里统一封装了一个跳转方法,不同场景自动选择router.push还是window.history.pushState。

还有一点,主应用如果用了Vue Router 4(Vue 3工程),方法和Vue Router 3几乎一样,但在qiankun的场景下要注意history.pushState和路由实例可能会出现不同步。如果你在某个时刻手动改了URL(比如通过history.pushState),Vue Router内部并不知道URL变了,需要手动执行路由实例的匹配逻辑,否则页面不会更新。

2.2 history模式下主应用页面跳转与微应用的坑

主应用在当前停留微应用页面时,如果直接在主应用代码里写this.$router.push('/some-main-page'),大部分情况下是可以工作的,但有一个很常见的坑:主应用路由的beforeEach守卫里如果写了类似“判断是不是微应用路径,然后next(false)”的逻辑,跳转就会被拦截。

我之前还遇到过另一个问题:主应用里放了多个微应用,微应用A的activeRule是/app-a,微应用B的activeRule是/app-b。我在主应用页面里点击菜单切换到微应用B,如果用的是this.$router.push('/app-b/home'),qiankun能正确匹配并加载微应用B。但如果先进入了/app-b/home/123这样一个二级路径,再切回/app-b,qiankun会发现URL变回/app-b,可能会重新触发微应用B的加载流程,而不是只做一次路由切换。

这点非常关键。qiankun的activeRule匹配的是“前缀”。当URL前缀从/app-b/home/123变为/app-b时,前缀/app-b仍然存在,qiankun会认为微应用B仍然激活,不会卸载也不会重新加载。但如果你是从/app-b切到/app-a,前缀变了,qiankun会先卸载B再加载A。卸载过程是异步的,如果你的代码里在router.push之后立刻去操作DOM或查询元素,有可能会拿到旧应用残留的内容或者报出“node is not found”之类的错误。

所以主应用内做跨应用切换时,最好用一个包装方法,里面加入合理的异步延时或afterUnload回调,等qiankun完成卸载和加载后再执行后续逻辑。我给的兜底方案是:

// 主应用暴露一个全局跳转方法 function switchTo(appPath) { const loadingApp = microApps.find(app => appPath.startsWith(app.activeRule)) if (loadingApp && loadingApp.status === 'NOT_LOADED' || loadingApp.status === 'UNMOUNTED') { // 如果目标应用还没加载,先加载,再跳转 loadMicroApp(loadingApp).then(() => { window.history.pushState({}, '', appPath) }) } else { window.history.pushState({}, '', appPath) router.push(appPath) } }

这个思路可以应对多数主应用内跨应用切换的场景,但细节上还需依据你的qiankun版本来调整事件监听方式。如果你用的是qiankun 2.x,loadMicroApp是可用方法;如果用的是1.x,API会有些出入,需要参考对应版本文档。

3. 主应用与微应用之间的跳转:最常用的三种手段

3.1 主应用跳转到微应用:菜单点击触发的标准操作

最常见的一种场景就是主应用的侧边栏菜单点击后,跳转到某个微应用的首页。我推荐的做法并不复杂:

  1. 菜单项数据里,为每个菜单配置一个path字段,比如/order/home、/user/list
  2. 点击菜单时,直接调用主应用的路由实例router.push(menuItem.path)
  3. qiankun根据activeRule自动加载对应微应用

这个方案之所以推荐,是因为它完全依赖qiankun的“路由驱动”机制,不需要手动管理子应用的生命周期。主应用只需要在注册微应用时把activeRule、entry、container配置好:

registerMicroApps([ { name: 'order-app', entry: '//localhost:3001', container: '#micro-app-container', activeRule: '/order' }, { name: 'user-app', entry: '//localhost:3002', container: '#micro-app-container', activeRule: '/user' } ]) start()

之后点击“订单管理”菜单,执行router.push('/order/home'),qiankun就会自动匹配到/order前缀,加载订单微应用,并将/order/home这个URL传给子应用。子应用内部的路由再根据base='/order'解析出真正的页面。

3.2 微应用跳转到主应用:通过props传递跳转能力

微应用不能直接操作主应用的路由实例,因为qiankun在隔离环境里运行子应用,子应用拿不到主应用Router上下文。那子应用想跳回主应用怎么办?我见过很多团队的做法是:让子应用直接改window.location.href,这确实能跳,但代价是整页刷新。在表单填写了一半、弹窗开着的情况下整页刷新,用户会崩溃。

更优雅的做法是,在registerMicroApps时通过props向子应用传递一个跳转方法:

registerMicroApps([ { name: 'order-app', entry: '//localhost:3001', container: '#micro-app-container', activeRule: '/order', props: { navigateToMain: (path) => { window.history.pushState({}, '', path) // 手动通知路由实例处理URL变化 router.push(path) } } } ])

子应用在自己的main.js入口处接收props,然后挂载到Vue原型或全局状态里:

export async function mount(props) { // props里就有主应用传过来的navigateToMain Vue.prototype.$navigateToMain = props.navigateToMain // 或存入Vuex store.commit('SET_NAVIGATE_TO_MAIN', props.navigateToMain) const instance = new Vue({ router, store, render: h => h(App) }) instance.$mount('#app') }

然后在子应用的任意组件里,就可以这样跳回主应用:

this.$navigateToMain('/home')

我实际用下来的体验是,这个方案比window.location.href要好很多,因为它是纯前端路由级别的跳转,不走整页刷新,主应用切换回/home页面,子应用会正常卸载,内存中也不会残留子应用未销毁的事件监听器。

3.3 子应用内部正常路由跳转和主应用无感

子应用内部页面之间的跳转,其实和普通单页应用没有任何区别。你在订单微应用里,从订单列表/order/list跳到订单详情/order/detail/123,直接用自己Vue Router的router.push就好。

但有一点要注意:子应用内部跳转时,URL会发生真实变化,从/order/list变成/order/detail/123。这时候qiankun的主应用路由并不会感知到URL变化(因为qiankun只关心前缀是否匹配),所以不会触发重新加载子应用的操作。这没问题。可一旦用户在子应用内刷新页面,浏览器会重新加载整个HTML,主应用会启动,qiankun看到URL是/order/detail/123,匹配到订单微应用,再次加载子应用。整个过程是完整的。所以子应用内部路由跳转,不需要额外处理。

真正麻烦的是刷新后404的问题。如果你部署后没有把Nginx的try_files配置成try_files $uri $uri/ /index.html,刷新一个/order/detail/123深链接时会直接404,因为服务器上根本没有这个物理路径,只有根目录的index.html。我遇到过很多次,明明本地开发一切正常,部署到测试环境一刷新就白屏或404。排除方法很简单:先看是不是Nginx配置漏了,再看主应用加载够不够快。

3.4 利用全局状态配合跳转

在3.2里我们用了props传递跳转方法,这已经够用了。但有一种更灵活的做法是通过qiankun的GlobalState来配合跳转。

// 主应用里初始化全局状态 initGlobalState({ currentUser: null, lastPath: '/home' })

子应用通过onGlobalStateChange监听状态变化,在某个状态变更后执行跳转:

actions.onGlobalStateChange((state, prev) => { if (state.gotoPath && state.gotoPath !== prev.gotoPath) { router.push(state.gotoPath) } })

这个方案的好处是“解耦”。主应用不需要把跳转方法暴露给子应用,子应用也不需要依赖主应用的方法,只要大家约定好一个状态字段即可。缺点是间接层变多,容易造成状态满天飞,调试起来稍微费劲。如果只是解决主微应用跳转问题,props传递方法更直接,如果还要顺带传一些业务数据,那GlobalState确实是个不错的选择。

4. 微应用之间的互相跳转:核心思路是“借道主应用”

4.1 微应用A跳微应用B的最可靠方案

微应用A要跳转到微应用B,最直接的想法是“A直接改URL到B的地址”。比如:

window.location.href = '/user/list'

这样确实能跳到微应用B,而且qiankun会卸载A、加载B。但代价是整页刷新。另一个变体方案是用window.history.pushState:

window.history.pushState({}, '', '/user/list')

这样URL变了,qiankun如何感知?qiankun内部监听了popstate事件,但pushState并不会触发popstate。所以如果你只执行pushState而不做其他操作,qiankun很可能不会去加载微应用B,页面停留在A,而URL却是B的地址——看起来像是A里出了一个Bug。

所以最可靠的方案是:微应用A通过props里的跳转方法,先跳回主应用,再由主应用路由跳转到微应用B。用代码表示就是:

// 子应用A内部,拿到主应用传入的跨应用跳转方法 this.$navigateToMain('/user/list')

主应用的navigateToMain方法接收到/user/list,执行router.push('/user/list'),qiankun看到URL前缀变成/user,自然卸载A、加载B。整个过程不会整页刷新。

如果还是想从A直接调B,不走主应用“中转”,也可以直接在主应用里给子应用传一个navigateToApp方法,里面先去判断目标应用是否已加载,再执行加载和跳转。但这个方法实现起来略微复杂,需要有主应用Vue Router实例配合。所以我建议没有特殊需求的话,统一用“借道主应用”方案,逻辑清晰、容易排查。

4.2 带参数跳转和回退注意事项

微应用A跳微应用B,通常还要带参数,比如从订单详情页跳到用户详情的ID。参数放哪里?

  • 放在URL路径里:/user/detail/123,简单直接,刷新不丢参数
  • 放在URL query里:/user/detail?id=123,也还直观,但有些场景下会污染URL
  • 放在GlobalState里:不污染URL,但刷新后会丢

我一般建议,重要的业务参数放URL路径或query里。经历过一次痛苦的调试后,我就彻底放弃了把已选商品、订单号这类核心参数塞在GlobalState里的想法——用户一刷新,参数全没了,页面直接空白。

跳转后怎么回退?比如从订单微应用跳到了用户微应用,用户点浏览器“返回”按钮,希望回到订单详情页。这里有个关键点:如果用的是router.push,浏览器历史栈里会多一条记录,返回是可以回到上一页的。如果用的是window.location.href整页跳转,返回时会重新加载之前的页面,微应用的加载状态会被重建,但页面也勉强能回来。

但如果你的子应用A是通过router.replace这种方式跳转的,历史栈被替换了,返回就不会回到A页面。所以在设计跨应用跳转时,要想清楚是“暂时性的跳转”(应该可以返回)还是“永久性的切换”(不需要返回)。两种语义对应push和replace,别搞混。

4.3 子应用内绝对路径跳转和相对路径跳转的差异

在qiankun里,子应用内部跳转时,Vue Router的base决定了路由解析的根路径。比如你在子应用B里,base是/user,那么:

this.$router.push('/detail/123')

实际浏览器URL变化是/user/detail/123。这里写的是“绝对路径”,但它是在子应用的base之上拼的,不是从根域名计算的。严格来说,Vue Router内部会自动把base前缀加上,所以最终URL看起来是从根开始。

如果你写的是相对路径:

this.$router.push('detail/123')

那会基于当前路由往下拼。如果当前是/user/list,就是/user/list/detail/123。很多初学者在这里踩坑:明明想跳详情页,出来的URL是/user/list/detail/123,再刷新就404。所以“子应用内跳转”尽量写绝对路径,避免路径嵌套污染。

我在qiankun项目中有一条强制约定:所有子应用内部跳转,路径必须以/开头并携带完整子应用内部路径,比如/detail/123,配合base拼成完整主URL。这条约定我一直沿用到现在,跨应用跳转也从没再出过路径嵌套问题。

5. 路由模式统一与URL直接访问的处理方案

5.1 地址栏直接输入子应用URL的兼容处理

你是否有过这样的体验:在地址栏直接输入https://example.com/order/detail/123,期望直接进入订单微应用的详情页。在纯前端开发环境里,敲回车后浏览器会向服务器发起请求,如果服务器没有配置正确的try_files,大概率返回404。即便返回了index.html,主应用启动后qiankun会去加载订单微应用,子应用内部再解析/order/detail/123。

所以,要实现“地址栏直接输入子应用URL并正常打开”,需要三层都给力:

  1. Nginx或服务器配置:所有路径都回退到index.html,这一步很多团队会漏
  2. qiankun注册配置:子应用activeRule与URL前缀一致
  3. 子应用路由base:必须设置为activeRule对应的前缀

只要这三层全对,地址栏直接输入任意子应用深链接都能正常打开。我自己在排查“为什么我直接访问URL打不开子应用”时,通常按照这个顺序检查,基本能立刻定位问题层次。

5.2 Vue Router / React Router 内部跳转与浏览器URL变化的关系

很多人会混淆Vue Router内部跳转和浏览器URL的关系。简单理解:Vue Router的push底层就是调用history.pushState,只是后面还多做了“路由匹配并重新渲染组件”这件事。qiankun的跳转驱动本身依赖浏览器URL前缀,所以只要你通过任何方式让URL前缀变成某个子应用的activeRule,qiankun就有机会触发加载逻辑。

但有一个前提是,qiankun要能“听到”URL的变化。如果只是window.history.pushState,qiankun没监听这个事件就难以自动触发加载。有人会问,那为什么qiankun官方示例里主应用用router.push就能正常跳转子应用?因为Vue Router的push在执行时不仅改了URL,还在内部通过popstate等机制触发route更新,而qiankun监听了路由变化相关事件,实际上监听的是popstate,严格来说Vue Router变更时并不会触发popstate。那主应用是怎么感知的?

实际上qiankun内部对路由变化的感知,是通过监听popstate和pushState方法重写等方式实现的。在某次qiankun迭代中,已经对pushState做了方法包裹,所以主应用模块里通过history.pushState触发URL变化时,qiankun能感知。

这也是为什么在子应用里直接执行window.history.pushState不一定稳妥的原因——子应用运行在隔离环境里,它的window很多时候并非主应用的原生window,qiankun对它的处理跟主应用不太一样。所以别在子应用里手动操作history,除非你很清楚自己在做什么。

5.3 基于hash模式跳转的兼容思路

有些旧项目,子应用一直用的是hash模式,比如URL是https://example.com/#/order/detail/123。这种模式下qiankun匹配activeRule时会有些特殊。因为hash部分不会发送到服务器,所以服务器不用担心404,但qiankun的activeRule匹配的是window.location.pathname和window.location.hash的组合,官方默认支持hash模式匹配。

如果你子应用用的是hash模式,主应用想跳过去,URL应该是:

https://example.com/#/order/detail/123

子应用的base可能是/,因为它所有路由都挂在hash后面。这种情况下跨应用跳转时,要注意拼URL的格式必须是#/order/...,而不是直接改pathname。简单说,hash模式下的跳转更“宽容”,但我不建议主应用和子应用混用两种模式,因为排查问题时要时刻想着现在是基于hash还是history,心智负担太重。

6. 我踩过的那些跳转大坑与排查实录

6.1 跳转后白屏,但控制台没有任何报错

这是微前端跳转问题里最常遇到、也最让人抓狂的现象。URL变了,子应用没加载出来,白屏,控制台干干净净。

我第一次遇到时,排查了很久,最后发现是子应用挂载容器被销毁了但没有在qiankun要求的时间里重新创建。qiankun的container如果指定的是#micro-app-container,主应用在进行路由切换时,如果误把这个容器对应的DOM节点删掉或隐藏,子应用就找不到挂载点。

还有一种情况:主应用给子应用传了props,子应用等待props异步获取权限数据,权限数据还没回来,页面就处于空白状态。我见过团队把等待弹窗做成一张空白页,用户看起来就是白屏。排查时可以这样验证:在地址栏手动刷新子应用URL,如果能正常加载,说明问题跟跳转逻辑无关,而是跳转过程中少了某些初始化步骤。

6.2 子应用可以打开,但刷新就404

这个问题前面提过多次,这里补充一个更容易被忽视的点:很多团队的主应用和微应用其实是部署在同一个域名下的不同路径,比如主应用在/,订单微应用在/order/,用户微应用在/user/。部署时,Nginx配置应该是:

location /order { try_files $uri $uri/ /order/index.html; } location /user { try_files $uri $uri/ /user/index.html; } location / { try_files $uri $uri/ /index.html; }

如果Nginx把/order目录单独托管,而try_files没有回退到/order/index.html,而是回退到/index.html,那点击子应用内部路由后刷新,会先请求主应用HTML,主应用再根据URL去加载微应用,大概率也能成功,但如果主应用和子应用是通过不同构建流程打包的,子应用的资源路径相对于主应用根路径会有问题,表现还是404或资源加载不了。所以部署层面的try_files必须按“子应用目录独立回退”配置。

6.3 子应用跳转主应用后,主应用组件不更新

有时从微应用跳到主应用页面,URL正确,主应用壳子出来了,但那个页面的组件数据没有重新加载。原因是主应用路由组件复用了,Vue的beforeRouteEnter或created钩子不会再次执行。

需要在主应用里对路由跳转做统一处理,监听路由变化并重新拉取数据。比如:

watch: { $route() { this.fetchData() } }

这样从任意微应用跳回主应用,都能保证数据刷新。这个看起来是微前端跳转问题,实际上是单页应用本身的路由复用问题,但在微前端场景下更容易暴露出来,因为微应用和主应用之间的数据传递太容易让人忽略“主应用页面也需要更新”这件事。

6.4 使用全局状态跳转导致的状态不同步

用GlobalState做跳转时,最常见的问题是:A应用设置了gotoPath,B应用监听这个字段去跳转,但是A应用里可能同时设置了其他字段,B应用把整个state都拿到了,却不知道该听谁的。

我的建议是,约定一个专门的跳转协议字段:

// 主应用初始化全局状态 initGlobalState({ navigation: { path: '', query: '', timestamp: 0 // 保证每次跳转都是新的 } })

B应用监听到navigation.timestamp变化,就去解析path和query并跳转。加时间戳是为了防止同一个URL连续跳两次时不触发变更。这种方案我用下来比裸传一个字符串字段可靠很多,至少不会出现重复跳转或漏跳转。

6.5 子应用loaded但不显示,路由匹配没执行

还有一次,微应用加载了,mount生命周期也执行了,但页面空白。最后发现是子应用的base没配对的锅。qiankun把URL设置为/order/detail/123,但子应用Vue Router的base配置成了/,Vue Router去匹配/detail/123时怎么都对不上路由表。因为在子应用的路由表里,根本没有/detail/123这种根路径开头的路径,它的路由路径是/order/detail/123或者配了嵌套路径。

解决方法是把子应用Vue Router的base设置为qiankun的activeRule:

const router = new VueRouter({ base: window.__POWERED_BY_QIANKUN__ ? '/order' : '/', mode: 'history', routes })

这段代码在qiankun官方文档里也有示例,但在实际项目里很多人要么没看到,要么写了但写错了。我一直强调:子应用单独开发时要保持base为/,在qiankun环境里要动态切到activeRule前缀。用window.__POWERED_BY_QIANKUN__做判断是最稳妥的做法。

6.6 qiankun 2.x与单应用模式下DevServer的跨域配置

开发环境下,子应用跑在localhost:3001,主应用跑在localhost:8080,它们之间是跨域的。qiankun会通过fetch拉取子应用的HTML,再解析JS、CSS。如果子应用DevServer没有开启跨域头,qiankun拉取失败,你看到的跳转结果是“点击菜单没反应,或者报错”。

解决方式是子应用Webpack DevServer配置:

devServer: { port: 3001, headers: { 'Access-Control-Allow-Origin': '*' } }

这个配置我基本在初始化脚手架时就会写好,避免项目跑起来后遇到跳转问题还要中途插一脚。很多人会在这里卡很久,因为在浏览器里直接访问子应用地址是正常的,但在主应用壳子里就是加载不出来,跳转自然也没效果。

7. 跳转方案选型与封装建议

7.1 中央跳转管理器的价值

经历过这些坑之后,我的做法是在主应用里封装一个“中央跳转管理器”,所有应用之间的跳转都走这一条路。核心简化代码如下:

// 主应用里创建 navigationManager const navigationManager = { goMain(path) { router.push(path) }, goApp(appName, path, query = {}) { const targetPath = `/${appName}${path}` router.push({ path: targetPath, query }) }, replaceMain(path) { router.replace(path) }, replaceApp(appName, path, query = {}) { const targetPath = `/${appName}${path}` router.replace({ path: targetPath, query }) } }

在注册微应用时,将navigationManager传入props。然后所有子应用内部只认这个manager对象,不再直接操作window.location或history。好处非常明显:

  • 跳转逻辑全部集中在一个地方,后续如果要加埋点、鉴权、路由兜底,只需要改主应用一处
  • 子应用开发人员不需要关心qiankun的实现细节,直接调用props.navigationManager.goApp('user', '/detail/123')就能跳转
  • 排查问题时思路清晰:跳转出错,先看主应用的manager实现,再看具体传参

7.2 路由守卫里处理统一的登录态与权限

跨应用跳转时,经常遇到一个问题:应用A已经登录了,但应用B还要再验证一次权限。如果每个应用各自校验,体验很差。更合理的是在主应用路由守卫里统一校验登录态:

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (!token && to.path !== '/login') { next('/login') } else { next() } })

子应用不再自行校验token,而是在mount时从主应用的GlobalState里拿用户信息。这样子应用跳转时不会因为“尚未登录”被打断,也很少出现跳转后又被踢回登录页的情况。

这个设计虽然不属于“跳转方式”本身,但却是跨应用跳转能否顺畅落地的关键前提。如果每个应用各自有独立的权限判断,你从A跳B时就会被B的登录拦截挡住,用户以为系统出错了。所以做跳转方案时,权限模型也得一并考虑。

7.3 何时不应该用qiankun的跳转而是用业务接口

最后想说一个不是技术的坑:不是所有“看起来像跳转”的操作都适合走前端路由。比如用户从订单微应用跳去用户微应用,是想查看某个用户的详细档案,这两个应用之间可能根本没有统一的会话状态。这时“跳转”其实应该先调用后端接口,校验该用户在当前业务域是否有查看权限,再决定放不放开页面。

如果把权限校验放在前端跳转里做,等于把重要的安全逻辑暴露给了攻击者。所以做好跨应用跳转,不只是技术问题,还是一个业务边界问题。先想清楚:这次跳转,是纯界面切换,还是带权限校验的业务流转。两者对应的实现深度完全不同。

8. 一个经验引以为戒:先设计跳转规范,再写业务

我在多个微前端项目里吃过亏,血的教训是:跳转规范必须在项目起步时设计好,不要等业务写了一半再回头补。因为一旦子应用各自为政,有的用window.location.href,有的用props跳转,有的在GlobalState里监听跳转,整个项目会变成一团乱麻。

好的起步方式是:

  1. 文档里定义好四类跳转场景的API
  2. 主应用实现navigationManager
  3. 每个子应用的入口文件中,统一挂载navigationManager
  4. 各子应用代码里禁止直接改window.location和history

这样做之后,后面的业务开发基本不会踩跳转的大坑。就算踩了,你也能通过navigationManager的统一日志快速定位问题,而不是在多个子应用之间翻来翻去。

qiankun作为微前端框架,本身解决的是应用加载、隔离、通信,跳转这块更多是“约定优于配置”。只要大家在业务代码里遵循统一的跳转规范,把主应用当作中枢,子应用之间的跳转就会像本地路由跳转一样自然。别让跳转成为微前端项目里最闹心的部分,提前设计,给团队省下大量排查时间,这是我掏心窝子的建议。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询