前端微服务技术选型及页面集成方案

2,274 阅读10分钟

如果项目经理提到了想接入其他项目的页面,又或者是新平台需要实现允许别的项目进行接入的功能,而你对此一头雾水不知如何起步。那么本文就是为你而写的,这篇文章会介绍该如何根据项目情况选择微服务技术栈,以及对相关的原理和优点进行介绍,让你在跟项目经理扯皮的时候有理可依。

不用担心,没有你想象的复杂。

如何选择?

其实现在前端微服务能选择的技术并不多,经典的 iframe,老牌的 single-spa,国产的 qiankunice-stack,webpack5 的 Module Federation(以及在此基础上构建的 EMP)。

我们先说结论:优先用 qiankun,不行就用 iframe,我做过的微服务集成里,用这两者几乎就可以覆盖所有需求了。而这俩具体用哪个主要取决于 自己能不能修改对应项目的代码

如果说是采购的别家的平台,别人自然不会让你改代码,或者说只能沟通需求,让对方的程序员去修改代码。这时候如果你给对方说我需要你变更 XXX 构建配置,引入 XXX 包,代码上做 XXX 修改,对方只能给你单走一个 6。这时候 iframe 就可以派上用场。可以说,如果项目里需要集成采购的第三方成熟产品的话,iframe 几乎是必须要有的。

而如果要集成的页面是自己公司的内部项目,或者这个项目本身就是你来负责的,那么就用 qiankun 完成微服务接入。至于为什么不用上面提到的其他方案,原因就是 ice-stack 和 Module Federation / EMP 都对子应用的项目工程有限制。

例如 ice-stack 需要子应用引入对应的 npm 包,这就要求必须是现代前端工程。所以如果你需要接入一个 jq 或者其他没有构建流程的前端项目,那这一步就直接卡死了。

而联邦模块则要求项目必须使用 webpack5,可用范围更小了。

对于现阶段常见的前端微服务需求来说,基本都是需要集成多个现存的、多种技术栈、可能无人维护的前端应用,或者说一个做了好几年的巨石项目,现在要用微服务模式来逐步重构代码。无论哪一种情况,尽可能不动子应用的代码 都是优先级非常高的需求。

而 qiankun 则非常好的解决了这个痛点,不需要引入额外的包,几乎不需要深入项目进行改造。让你不需要在屎山项目上耗费太多精力,就能让其以微服务的形式跑起来。


OK,现在总结一下,首先你要了解自己项目里都要集成哪些子应用,并明确自己对这些项目有多少控制权,一般可以分为下面三个等级:

  • 完全可以修改前端代码
  • 不能接触到代码,但是可以和对方技术沟通并协商集成方案
  • 不能接触到代码,并且对方找理由说不能改代码(比如要到下个版本才能改、这个需求我们会收集反馈给技术...)

如果是自己可改,那就上 qiankun,如果不能接触到代码,就iframe,简单粗暴。

下面我们会针对这三者如何进行页面集成进行说明,不过在此之前,我们还是要先了解下 iframe 和 qiankun 的优势和适用领域都有那些。

qiankun 对比 iframe

你可能已经在很多文章里看到过类似的介绍了,所以本文不再赘述,如果你没有看过的话,可以点这里先了解一下:Why Not Iframe,文章很短。

简单来说 qiankun 以需要修改子应用代码为代价,换取了更好的,近乎无缝的使用体验。而 iframe 虽然兼容性好,适用范围广,但是使用体验要差一点。特别是 iframe 里的路由 history 不会同步到浏览器的地址栏里,导致前进后退按钮也无法正常使用,非常影响用户体验,而 qiankun 就不会出现这个问题。

所以说,对于那些核心业务(用户会经常点的),尽量使用 qiankun,只有实在搞不定的情况下,再去降级考虑使用 iframe。

页面集成方案

讲完了如何选择技术,现在来聊一下如何进行页面集成首先可以明确的是,几乎所有的页面集成都离不开单点登录,也就是下面这个流程:

  • 基座应用前端请求基座后端,要发起针对某某平台的单点登录
  • 基座后端和被接入方后端交互,获取单点 token,然后在响应里把 token 返回给基座前端
  • 基座前端携带 token 以指定格式访问被接入方前端
  • 被接入发前端识别到基座前端传来的 token,并向被接入发后端验证是否正确

无论是 qiankun 微服务还是 iframe,接入流程都是这个。

不过第一步不一定是必须的,因为如果要接入的子应用都是集群内部的话,其 token 有可能是通用的,直接拿给子应用就可以,所以这个要提前找后端确认好。

1、qiankun 基座平台微服务接入

接下来看具体的流程,在此之前先简单介绍一下 qiankun 的 api,非常简单,和接入地图或者图表的流程是几乎一样的,一共有两种方式:

  • 第一张方法是把微服务绑定到路由:
import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'react app',
    entry: '//localhost:7100',
    container: '#yourContainer',
    activeRule: '/yourActiveRule',
  }
]);

start();

注意其中需要的四个参数,name 是子应用名字,需要是唯一的,entry 是子应用的前端资源地址,说白话就是你直接访问这个网址就可以直接打开子应用。第三个是页面容器,和地图图表一样,它需要知道你把微服务的页面放在哪个地方。第四个就是要监听的路由了,当地址栏里的路由命中 activeRule 是,qiankun 就会去页面上找 container 并将其初始化成一个“沙箱”,最后把子应用的资源塞进去。

  • 第二种方法是手动加载微服务:
import { loadMicroApp } from 'qiankun';

loadMicroApp({
  name: 'app',
  entry: '//localhost:7100',
  container: '#yourContainer',
});

可以看到不需要传 activeRule 了,因为执行 loadMicroApp 时 qiankun 就会直接在页面上找 container 并初始化微服务。


那么这两种应该怎么选择呢?其实要看的是 微服务加载之前是否需要有其他工作要做。比如刚才说的,在加载微服务前需要先请求接口拿到 token,或者其他的异步操作。这时候就应该使用第二种方法手动加载微服务。

不然如果选第一种的话,路由切换了直接就加载微服务,这时候 token 还没到,微服务进去之后就直接给你弹回到登录页了。

有人可能会问:那我在点击微服务的入口按钮时就请求接口,然后请求到了之后再跳转微服务路由不行么?可以,但是不推荐。

因为 用户可能没有到入口页,而是通过地址栏直接进到了微服务路由,这种情况下你“点击入口按钮请求接口”那部分工作就被忽略掉了。也就是说你微服务的路由里是必须要做这一层鉴权工作。


除了上面执行单点的接口,你还需要找后台确认微服务的基本信息如何提供,即上面 qiankun registerMicroApps 或者 loadMicroApp 里的 name 和 entry 字段,如果你要接入的子应用比较多的话,这些信息最好还是由后台接口提供,不然每新增一个平台就要改动前端代码也是挺烦的。

2、qiankun 子应用修改

除了 qiankun 提到的 子应用修改 外,你还需要确认子应用是否有消化单点 token 的能力,因为基座应用最后会携带着 token 访问子应用的前端,这就需要子应用可以正确识别到 token 并将其转换为本地应用的登录状态。

例如最常见的提供一个 /sso 路由,这个路由接受 token 和 next_url,即 /sso?token=abc&next_url=%2Fhome 这个路由会专门负责单点相关的状态恢复,并在登录完成后重定向到 next_url。又或者识别 token 的组件在路由树的根节点里,这样子应用的跳转路径应该是 /home?token=abc,两种方式都可以,第二种相对更安全一点。

除了单点登录之外,还需要设置是否隐藏标题栏和侧边栏,由于我们用了 qiankun,所以直接在 loadMicroApp 里通过 props 把是否显示的参数传给子应用就可以了。这个需求还是挺普遍的,因为集成进来的页面几乎都要求使用基座平台的 header 或者侧边栏,所以在适配的时候最好支持三种情况(单独隐藏子应用 header,单独隐藏子应用侧边栏,两个一起隐藏)

这样就用 qiankun 完成了我们刚才提到的单点全流程登录。

3、iframe 引入:可以协调集成方案

接下来讲一下 iframe 引入的第一种情况,我们刚才提到,如果接入的是第三方服务的话,可能会出现下面这个情况:

不能接触到代码,但是可以和对方技术沟通并协商集成方案

这时候需要和对方沟通的就是上一小节里讲的内容:

  • 用什么格式把单点 token 传给他们前端。
  • 他们前端怎么隐藏自己的标题栏和侧边栏,比如说传递一个参数 https://sub-app/home?layout_type=no_header

3、iframe 引入:不能协同集成方案

如果对方的产品已经很成熟了,不能改代码或者改起来很慢,那先按照上面的流程沟通如何单点登录和怎么隐藏标题侧边栏。

如果对方平台不支持单点登录的话,那不用搞了,建议把问题上升给项目经理。这种情况下就算集成进来也会显示一个登录页,需要二次登录。

如果对方平台不支持隐藏侧边栏的话,可以用一些 css 技巧把要隐藏的内容挡住,例如 iframe 外部套一个 div,指定 overflow: hidden; position: relative;,然后把 iframe 设置成 position: absolute;,最后使用 topleft 偏移一个负数的尺寸,通过这种方式把侧边栏和标题栏隐藏起来。

又或者,你可以提意见,例如不通过页面集成的方式引入,而是弹窗、新标签页的形式加载对方平台。

总结

本文简单讲了当前前端微服务化的技术栈选型。一般来说没有特殊要求的话,qiankun + iframe 就可以很好的解决页面集成需求。

除了技术选型之外,还介绍了下 qiankun 和 iframe 的大致页面集成方案,以及在页面集成 / 单点登录时可能会遇到的一些问题。不是很详细,希望能有抛砖引玉的效果。