巧用serverless实现代理转发解决微前端跨域
巧用serverless实现代理转发解决微前端跨域
前言
痛点
- 多平台窗口之间切换复杂,往往不能准确点到想要的窗口或界面,客户展示时容易出现问题。
- 不同系统之间的数据不通,老板想要任意页面数据拼合在一个页面,展示多种数据,尽可能实现总览。
- 企业内运营多个后台管理系统,账号密码不一致造成额外记忆负担。
明确需求,寻找最低成本解决方法
如果说不限制成本,后台前台都动起来,以上问题可以解决的很漂亮。但无奈会议上否决了动作较大的方案,此事也就暂时告一段落。经过一段时间的思索我还是有了以下思路。
- 将某一页面嵌入到另一页面最常见的莫过于iframe标签了,但它并不能缓存实例,跳转页面后再回来它会重新渲染,不符合需求。
那主流微前端方案qiankun呢?简单实践后发现改造确实简单,但无奈需要改造的子应用太多,且每个改造完毕都需要重新部署,于我一个人做而言成本太高,还是不符合需求。
那有没有更容易改造子应用的微前端方案呢?有!microapp。
- 微前端的部署不可避免的就会提到跨域问题。一般情况下在生产环境中使用nginx即可解决,但遗憾我司目前使用的是tomcat,所以只能另辟蹊径。
如果要求后台去加cors头或者前端去加nodejs中间件不可避免的都要有服务端的参与,先编码再部署,涉及多个服务端,工程量大,影响也未知,并不是较好的解决方法。
那有没有其他方法可以实现代理转发呢?我找到的方法是serverless!
以下来逐一说明~~~
概念相关
微前端
不得不说微前端框架市面上推出的越来越多,最为流行的莫属qiankun。固然十分优秀,但并不满足我司需求,经过多方调研,注意到了与qiankun不同思路的microApp框架。
microApp借鉴了webComponent思想,通过customElement结合自定义的shadowDom,将一个一个子应用封装成一个一个类webComponent的组件,实现了子应用的组件化渲染。
这里说明一下我使用microapp的原因:
- 接入成本低,需求不高的情况下无需对子应用硬编码,可节省大量时间和精力。
- 支持应用缓存,非常方便的恢复用户操作行为。
- 支持预加载,对于我来说这是个非常重要的功能,因为有的服务器带宽仅开了3M大小,开启预加载后首屏渲染速度可以得到很大的提升。
- 扩展性强,可以满足日后可能出现的需求。
(注:具体是否需要改造子应用请查阅文档。)
以上仅仅是描述了microapp的个别优势,更多好用的功能还请前往文档了解。
serverless
直白说,serverless是概念,表示开发者无需关心“服务器”相关事项,只编写业务代码上传到运营商的平台调用即可。
我这里采用的是DCloud推出的unicloud服务,它由阿里云和腾讯云的serverless服务之上封装而成。部分人害怕和云厂商之间形成捆绑关系,unicloud可以自主切换供应商,就较好的解决了这个问题。本文采用的是阿里云服务。
说明一下我这里使用unicloud的原因:
- 成熟的轮子,基座应用可直接选用名为uni-admin的后台管理模板。功能齐全,拿来即用。(uniapp可开发PC端)
- 配合HBuilderX编码可以鼠标右键一键上传云函数,开发方便。
- 网页托管服务网页和资源可以直上cdn。
- 免费。免费。免费。
具体操作
架构设计
已知API服务是serverless最常用的落地形式。感兴趣可以看看这篇文章。

根据我司具体场景,触发云函数的时机只存在于前台,不可通过后台配合调用。所以我所想到的的架构如下图所示。

也就是说只要能将客户端真实发送的请求拦截并且替换为url化的云函数,就可以触发代理转发逻辑,返回给客户端带有cors头的响应数据。知道了核心方法接下来逐个解决就好了。
基座应用uni-admin改造
得益于微前端框架技术栈无关这个核心功能,uniapp技术栈也能发挥价值。这里我们对uni-admin进行小小的改造以适合不同的子应用界面。
页面布局调整
子应用的菜单栏有的在左有的在上,那么基座应用的菜单栏就需要适时的隐藏了。这里我想到的方式是为uniapp项目创建根组件。功能主要有三:1. 为菜单栏包裹抽屉组件。 2. 增加全局悬浮按钮呼出基座应用菜单。 3. slot插槽占位以便输出子组件。

效果如下图所示

microapp接入
1. 安装依赖
查看代码
npm i @micro-zoe/micro-app --save
2. 在入口处引入
查看代码
// index.js // 这里官方文档没有特别说明将此语句写在第一位,但根据qiankun的经验来看最好是在第一位。 import microApp from '@micro-zoe/micro-app' microApp.start()
3. 为子应用分配路由
查看代码
// router.js import Vue from 'vue' import VueRouter from 'vue-router' import MyPage from './my-page.vue' Vue.use(VueRouter) const routes = [ { // 👇 非严格匹配,/my-page/* 都指向 MyPage 页面 path: '/my-page/*', // vue-router@4.x path的写法为:'/my-page/:page*' name: 'my-page', component: MyPage, }, ] export default routes
4. 在MyPage页面中嵌入子应用
查看代码
<template> <div> <h1>子应用</h1> <!-- name(必传):应用名称 url(必传):应用地址,会被自动补全为http://localhost:3000/index.html baseroute(可选):基座应用分配给子应用的基础路由,就是上面的 `/my-page` --> <micro-app name='app1' url='http://localhost:3000/' baseroute='/my-page'></micro-app> </div> </template>
fetch拦截fetch-intercept的使用
我司API接口都带有cors跨域头,只是文档类型出于安全问题并不带有跨域头,所以我只需要拦截fetch请求即可。
使用方法
// @/api/fetchInterceptor.js import fetchIntercept from 'fetch-intercept'; const fetchInterceptor = fetchIntercept.register({ request: function (url, config) { return [url, config]; }, requestError: function (error) { return Promise.reject(error); }, response: function (response) { return response; }, responseError: function (error) { return Promise.reject(error); } }); function InitFetchInterceptor (Vue) { Vue.prototype.$fetchInterceptor = fetchInterceptor } export default { install(Vue) { InitFetchInterceptor(Vue) } }
// main.js 全局使用 import fetchIntercept from './api/fetchInterceptor' Vue.use(fetchIntercept)
注意这里可能会出现一个报错找不到whatwg-fetch模块。解决方法是在webpack external添加重启项目即可。issuse地址:https://github.com/werk85/fetch-intercept/issues/6。
完成上述步骤我们就可以全局拦截fetch请求了,在request钩子中抛出url化的云函数,就达到了替换请求url的效果。再将原有请求url以参数的形式一同发送给云函数,客户端的工作即结束。
微应用改造
我司需求下微应用无需改造!略!
云函数怎么写
上面说到云函数url化,实际就是以url的方式调用云函数,这里有两个小坑说明一下,
1. 阿里云云函数url化会自动触发下载,必须绑定自定义域名才能解决。腾讯云没有此问题。
2. url化后取参方式有所变动

具体转发逻辑也很简单:云函数接收参数-->发起请求-->返回数据。
这里提一下云函数中访问其他HTTP服务不用装axios啦!unicloud提供了uniCloud.httpclient.request()这个API。
'use strict'; // 云函数url化后如何访问:https://uniapp.dcloud.net.cn/uniCloud/http.html#request-url async function proxy(event) { // 客户端云函数url化后,这里解构获取参数 const { url } = event.queryStringParameters const res = await uniCloud.httpclient.request(url, { followRedirect: true // 开启3xx响应时自动重定向 // gzip: true // HttpClient 将自动设置 Accept-Encoding: gzip 请求头,且会自动解压带 Content-Encoding: gzip 响应头的数据 }) return { // 代表使用阿里云集成响应 mpserverlessComposedResponse: true, // 表示body是否为Base64编码 isBase64Encoded: true, headers: res.headers, body: res.data.toString('base64') } } exports.main = async (event, context) => { try { const res = await proxy(event) return res } catch (e) { return { mpserverlessComposedResponse: true, isBase64Encoded: false, statusCode: 500, headers: { 'content-type': 'text/plain' }, body: e.message, } } };
补充
我是否用到微前端?参考这篇。
微前端能否顺利实施还得看后台支持。如果有nginx网关和SSO单点登录存在,将会更加顺畅。
总结
这篇文章算是记录了从技术角度了解到痛点后的处理过程。先根据痛点理清需求,再技术调研获取最优实现。贯穿的主题就是提效降本。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)