吊打产品,脚踢运营---基于qiankun的微前端改造调研

110 阅读4分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情

温馨提示:本故事人物纯属虚构,如有雷同,皆是巧合

故事背景

一周前的某天,我的VP彦祖哥和产品经理枭某找到我,说现在有这样一个需求。

“咱们现在的XX平台产品,不是个云平台产品吗,这样就导致一个问题,大一点的客户认为说,他们在我们平台做业务,是帮我们在做流量,而不是他们帮他们自己在解决业务问题。”

我说:“咱们的数据都是从线下抽取的,只是单号依赖我们这边生成,我们是打破他们各业务间信息孤岛的桥梁啊。”

没等我说完,产品就把我打断了,“我不要你以为,我要客户以为,你先听听我们的想法再说”

...

“我们计划将平台登录页和VI进行改造,为有需求的客户提供适配他们公司品牌的配色和LOGO。。。”

“意思一个公司来一套代码呗?咱们平台标准不要了是吧?”

.....

此处略去扯皮的一万五千字

....

最终,决定这个需求要做,于是形成以下三个方案。

技术架构背景:采用的是SSO单点登录的方式,于是登录页是由后台直接提供的服务,未前后端分离,基于oauth2和gwt实现

技术难点:登录还是传统的form表单action提交的方式,众所周知,form表单提交的默认行为可是刷新浏览器!此处是大坑,下面会说到。

  • 方案1 基于iFrame的方式,在业务系统内嵌入登录页的iframe,隐藏起来,根据页面参数生成各企业独特的登录页,登录按钮点击后,通过postMessage的方式调用iframe内的sso统一登录的表单提交方法实现登录。【问题:浏览器安全策略限制跨域iframe直接刷新页面,form表单提交后会被拦截,而且会有x-frame-option限制跨域iframe的加载,本身sso限制在iframe内运行】

  • 方案2 将sso登录页表单原生提交改造为ajax提交的方式,后台不再返回302重定向码而是正常将token返回 【问题:通过ajax提交的时候,服务器没办法写入session的cookie,导致业务系统校验时,认证失败】

  • 方案3 基于微前端将项目进行改造,实现在业务系统内直接加载sso登录页,并通过参数绘制各自企业的样式 最终确定为这个方案

qiankun 调研

qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。

我们的业务系统是Vue,SSO是jquery项目,所以我们只需要关注非 webpack 构建的微应用 即可,我们将业务系统作为主应用,接入qiankun,并将以/sso开头的作为我们加载单点登录子应用的路由入口

主应用内注册sso微应用

import { registerMicroApps, start } from 'qiankun';


registerMicroApps([
  {
    name: 'sso site', 
    entry: '//xxxx.com/',
    container: '#ssoContainer',
    activeRule: '/sso',
  },
]);


start();

sso微应用内处理

  • 处理 静态资源,相对路径改为绝对路径
  • 增加入口文件entry.js
<script src="//xxx.com/entry.js" entry></script>
  • 声明生命周期函数
const render = ($) => {
  $('#purehtml-container').html('Hello, render with jQuery');
  return Promise.resolve();
};


((global) => {
  global['purehtml'] = {
    bootstrap: () => {
      console.log('初始化');
      return Promise.resolve();
    },
    mount: () => {
      console.log('加载');
      return render($);
    },
    unmount: () => {
      console.log('卸载');
      return Promise.resolve();
    },
  };
})(window);

实现通信

  • props传参,适合初始化传递参数,比如本文中会把各企业信用代码通过props的方式传入
  • initGlobalState 主应用进行初始化,子应用通过props进行调用
props.onGlobalStateChange((state, prev) => {
    // state: 变更后的状态; prev 变更前的状态
    console.log(state, prev);
  });


  props.setGlobalState(state);

结语

也许产品和运营会提出很多看起来奇奇怪怪的需求,但他们都有真实的业务场景为依托,所以相杀不如相爱,认真思考每一个需求,这也是我们研发进步的动力呀