当前位置: 首页 > news >正文

2025前端微服务 - 无界 的实战应用


遇饮酒时须饮酒,得高歌处且高歌

在这里插入图片描述

文章目录

  • 什么是前端微服务
  • 主流框架概述
    • 无界 - 腾讯
    • 乾坤 - 阿里
    • Micro-app
  • Vue3项目引用
    • ⑴. 项目依赖安装
    • ⑵. main.ts 文件配置
    • ⑶. 路由配置
    • ⑷. 页面设置
  • 隐藏子应用菜单及顶部信息栏
  • 子应用样式冲突问题
  • 虚拟路由
    • ⑴. 路由
    • ⑵. 页面
  • 跨域问题解决方案
    • 开发环境
      • 主应用
      • 子应用
    • 生产环境
      • 主应用:
      • 子应用:
  • Nginx转发(未实现)
    • 主应用
    • 页面

什么是前端微服务

一个主应用(基座),内部嵌套了多个子应用

前端微服务是一种创新的技术手段与方法策略,其核心在于通过多个团队独立发布功能,共同构建现代化 Web 应用。通俗来说,就是一个 Web 应用中独立运行另一个 Web 应用的效果,极大地提升了应用开发的灵活性与可维护性。

在这里插入图片描述




主流框架概述

无界 - 腾讯

腾讯在维护的,后起之秀,非常轻量,4k star,无痛接入 vite。

官网: https://wujie-micro.github.io/doc/

在这里插入图片描述


  • 优势:
    • 低成本: 主应用和子应用的适配成本都极低。
    • 高速度: 支持静态资源预加载和子应用预执行,提升首屏打开速度和运行速度。
    • 原生隔离: 通过Web Components + Shadow DOM实现css原生隔离,通过iframe实现js原生隔离。
    • 强大功能: 支持子应用保活、多应用激活、去中心化通信、vite框架支持、应用共享等。

  • 劣势:
    • 相对较新: 相较于 Qiankun.js 和 MicroApp,Wujie 较为新颖,社区和生态系统尚在发展中。
    • 文档和支持: 由于其新颖性,文档和支持可能不如 Qiankun.js 完善。

乾坤 - 阿里

该框架是蚂蚁在维护的,15.7k star,目前官方使用的是 webpack 作为构建工具,没有明确表示支持 vite,社区有 vite-plugin-qiankun 插件支持。

官网: https://qiankun.umijs.org/zh/

  • 优势:
    • 成熟度高: Qiankun.js 基于 Single-SPA,并针对中国开发者进行了优化和本地化,已经得到了广泛的应用和验证。
    • 生态系统完善: 提供了丰富的插件和工具链,支持快速集成和上手。
    • 灵活性强: 可以自由选择是否使用沙箱隔离、应用加载策略等,满足不同场景需求。
    • 社区活跃: 有较多的社区资源和支持,问题解决较快。

  • 劣势:
    • 复杂度高: 由于其功能强大,配置和使用相对复杂,对开发者的技术要求较高。
    • 性能开销: 在某些场景下,沙箱隔离机制会带来一定的性能开销。
    • 侵入性: 对子应用改造成本较大,从 webpack、代码、路由等等都要做一系列的适配。

Micro-app

由京东开发,star 5.5k, 是一个基于WebComponents的前端微服务框架,支持多种前端框架。

官网: https://jd-opensource.github.io/micro-app/

  • 优势:
    • 轻量级: MicroApp 体积小,性能较好,适合对性能要求较高的项目。
    • 简单易用: 上手简单,API 设计清晰,开发成本低。
    • 灵活性强: 提供灵活的加载和卸载机制,支持动态应用加载。

  • 劣势:
    • 功能较少: 功能相对较少,不支持某些高级特性。
    • 兼容性差: 对于不支持WebComponents的浏览器没有做降级处理。



Vue3项目引用

⑴. 项目依赖安装

# 安装依赖
npm i wujie-vue3 -S

⑵. main.ts 文件配置

修改 main.ts 文件:

// 引入wujie
import WujieVue from 'wujie-vue3'...app.use(WujieVue)
...

⑶. 路由配置

修改 router.ts 文件:

# 略

⑷. 页面设置

修改 index.vue 文件,嵌入子应用:

<template><WujieVuewidth="100%"height="100%"name="subApp":url="subAppUrl":props="{ proxy: true }":preload="true"/>
</template>
<script lang="tsx" setup>
import WujieVue from 'wujie-vue3'const subAppUrl= ref('http://localhost:3001')
</script>



隐藏子应用菜单及顶部信息栏

在代码中添加如下判断逻辑,可隐藏主应用不需要的子应用模块

    if ((window as any).__POWERED_BY_WUJIE__) {// 处理子应用 - 可以隐藏主应用不需要的模块...}



子应用样式冲突问题

通过组合使用 Shadow DOM 隔离、CSS 作用域重写和命名约束,可系统性规避样式冲突

<template><WujieVuewidth="100%"height="100%"name="biShengApp":url="biShengUrl":props="{ proxy: true, sandbox: { strictStyleIsolation: true,  // 启用严格样式隔离scopedCSS: true,            // 启用CSS作用域experimentalStyleIsolation: true, // 实验性样式隔离shadowDOM: false,           // 是否使用Shadow DOM隔离(可能有兼容性问题)} }":preload="true"/>
</template>
  • strictStyleIsolation: 确保基本的样式隔离机制仍然有效。
  • scopedCSS : 将子应用的样式限制在其容器内,防止样式泄漏到主应用或影响其他子应用。
  • experimentalStyleIsolation: 实验性的样式隔离功能,提供额外的样式隔离保障。
  • shadowDOM: 一种更强大的隔离方式,但可能会有兼容性问题,默认关闭。如果其他隔离方式不起作用,可以尝试将其设为 true。



虚拟路由

⑴. 路由

修改 router.ts 文件:

# 略

⑵. 页面

添加路由监听逻辑,根据路由变化动态设置子应用地址

<template><WujieVuewidth="100%"height="100%"name="subApp":url="subAppUrl":props="{ proxy: true }":preload="true"/>
</template>
<script lang="tsx" setup>
import WujieVue from 'wujie-vue3'const route = useRoute()
const subAppUrl= ref('http://localhost:3001')onBeforeMount(() => {// 监听路由变化if (route.path == '/subApp(router配置的url前缀)/') {subAppUrl.value = `http://localhost:3001`} else {// 将router中配置的路由拼接成子应用的路由地址subAppUrl.value = `http://localhost:3001/${route.path.replace('/subApp(router配置的url前缀)/', '')}`}
})
</script>



跨域问题解决方案

开发环境

主应用

修改 vite.config.ts 文件:

...return {base: env.VITE_BASE_PATH,root: root,// 服务端渲染server: {port: env.VITE_PORT, // 端口号host: "0.0.0.0",open: env.VITE_OPEN === 'true',// 本地跨域代理. 目前注释的原因:暂时没有用途,server 端已经支持跨域// proxy: {//   ['/admin-api']: {//     target: env.VITE_BASE_URL,//     ws: false,//     changeOrigin: true,//     rewrite: (path) => path.replace(new RegExp(`^/admin-api`), ''),//   },// },},

子应用

  • 服务端:
    • 接口跨域:接受跨域请求
    • 接口凭证:‘true’改为‘false’

生产环境

主应用:

编辑 nginx.conf 文件:

worker_processes  1;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;server {listen       9527;server_name  localhost;location / {root   html;index  index.html index.htm;}# 主应用接口转发location ^~/admin-api/ {proxy_pass http://localhost:48080/;client_max_body_size    2000m;proxy_send_timeout 1800s;send_timeout 1800s;# 增强headers配置proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header X-Forwarded-Host $host;proxy_set_header X-Forwarded-Port $server_port;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";# 优化cookie处理proxy_cookie_domain localhost:48080 $host;proxy_cookie_path / "/; secure; HttpOnly"; # 确保安全属性# 禁用缓存,确保每次请求都到达后端proxy_no_cache $cookie_session $http_pragma $http_authorization;proxy_cache_bypass $cookie_session $http_pragma $http_authorization;# 增强跨域配置add_header Access-Control-Allow-Origin $http_origin always;add_header Access-Control-Allow-Credentials "true" always;add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS, PUT, DELETE' always;add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,Set-Cookie' always;add_header Access-Control-Expose-Headers 'Set-Cookie' always;# OPTIONS请求处理if ($request_method = 'OPTIONS') {return 204;}# 日志配置access_log /var/log/nginx/admin-api.access.log;error_log /var/log/nginx/admin-api.error.log debug;# 增加请求体缓冲,防止大请求被截断proxy_request_buffering on;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}
}

子应用:

配置静态资源缓存、反向代理、跨域等相关内容

编辑 nginx.conf 文件:

# 在http区域内一定要添加下面配置, 支持websocket
map $http_upgrade $connection_upgrade {default upgrade;'' close;
}server {listen 3001;server_name localhost;#root /usr/share/nginx/html/platform;# docker host html files,使用外部文件,开发调试时用root /usr/share/nginx/hosthtml/platform;gzip on;gzip_comp_level  2;gzip_min_length  1000;gzip_types  text/xml text/css;gzip_http_version 1.1;gzip_vary  on;gzip_disable "MSIE [4-6] \.";# 静态资源缓存配置,同时包含CORS头location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {expires 1y;add_header Cache-Control "public";add_header Access-Control-Allow-Origin "*" always;add_header Content-Security-Policy "frame-ancestors *";}# 根路径,包含CORS头location / {try_files $uri $uri/ /index.html =404;add_header Access-Control-Allow-Origin "*" always;add_header Content-Security-Policy "frame-ancestors *";}# 后端服务反向代理,不需要包含CORS头,因为后端服务中已经开启跨域location /api {if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin "$http_origin" always;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always;add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;add_header Access-Control-Allow-Credentials "true" always;add_header Access-Control-Max-Age 1728000 always;add_header Vary "Origin" always;add_header Content-Length 0 always;add_header Content-Type "text/plain; charset=utf-8" always;return 204; # 返回 204 No Content}    proxy_pass http://backend:7860;proxy_read_timeout 300s;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $connection_upgrade;client_max_body_size 50m;# 添加必要的CORS头add_header Access-Control-Allow-Origin "$http_origin" always;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always;add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;add_header Vary "Origin" always;add_header Content-Security-Policy "frame-ancestors *";}location /workspace/ {alias /usr/share/nginx/html/client/;index index.html index.htm;try_files $uri $uri/ /workspace/index.html;add_header Access-Control-Allow-Origin "*" always;add_header Content-Security-Policy "frame-ancestors *";}location /workspace/api {rewrite ^/workspace(/.*)$ $1 break;if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin "$http_origin" always;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always;add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;add_header Access-Control-Allow-Credentials "true" always;add_header Access-Control-Max-Age 1728000 always;add_header Vary "Origin" always;add_header Content-Length 0 always;add_header Content-Type "text/plain; charset=utf-8" always;return 204; # 返回 204 No Content}    proxy_pass http://backend:7860;proxy_read_timeout 300s;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $connection_upgrade;client_max_body_size 50m;# 添加必要的CORS头add_header Access-Control-Allow-Origin "$http_origin" always;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always;add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;add_header Vary "Origin" always;add_header Content-Security-Policy "frame-ancestors *";}location ~ ^/(workspace/subApp|subApp|tmp-dir)/ {rewrite ^/workspace(/.*)$ $1 break;proxy_pass http://minio:9000;add_header Access-Control-Allow-Origin "*" always;add_header Content-Security-Policy "frame-ancestors *";}
}



Nginx转发(未实现)

实现思路:通过主应用配置子应用的url地址(例:/subAppUrl),Nginx监测到该地址时,将静态资源及api进行转发到真实地址(例:http://xxx.xxx.com)。

主应用

修改 nginx.conf 文件:

worker_processes  1;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;# 性能优化gzip on;gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;gzip_vary on;gzip_proxied any;gzip_comp_level 6;gzip_buffers 16 8k;gzip_http_version 1.1;server {listen       9527;server_name  localhost;# 全局 CORS 配置add_header Access-Control-Allow-Origin * always;add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;add_header Access-Control-Max-Age 1728000 always;# 处理预检请求location ~* ^/ {if ($request_method = 'OPTIONS') {add_header 'Content-Type' 'text/plain; charset=utf-8';add_header 'Content-Length' 0;return 204;}}location / {root  html;index  index.html index.htm;try_files $uri $uri/ /index.html;}location ^~ /admin-api {client_max_body_size 100M;client_body_buffer_size 100M;# 修正代理路径proxy_pass http://localhost:48080/admin-api;# 完整的代理头设置proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header X-Forwarded-Host $host;proxy_set_header X-Forwarded-Port $server_port;# 关键:传递所有客户端请求头proxy_set_header Accept-Encoding "";proxy_set_header Origin "";proxy_pass_header Set-Cookie;# 禁用缓存proxy_buffering off;# 超时设置proxy_connect_timeout 60s;proxy_send_timeout 60s;proxy_read_timeout 150s;# WebSocket支持proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";# 调试日志access_log logs/admin-api.access.log;error_log logs/admin-api.error.log debug;}# 微前端子应用代理配置location ^~ /subAppUrl {# 禁用缓存,确保实时获取内容proxy_buffering off;add_header X-Proxy-Location "sub-app";# 重要的代理头设置proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-Host $host;proxy_set_header X-Forwarded-Port $server_port;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;# WebSocket支持(如果微前端需要)proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";# 超时设置proxy_connect_timeout 60s;proxy_send_timeout 60s;proxy_read_timeout 60s;# 调试日志access_log logs/sub-app.access.log;error_log logs/sub-app.error.log debug;# 转发请求到微前端应用服务器rewrite ^/subAppUrl(.*) $1 break;proxy_pass http://你的真实地址:端口号;}# 静态资源缓存配置location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {expires 7d;add_header Cache-Control "public";}}
}

页面

修改 index.vue 文件:

<template><WujieVuewidth="100%"height="100%"name="subApp":url="subAppUrl":props="{ proxy: true }":preload="true"/>
</template>
<script lang="tsx" setup>
import WujieVue from 'wujie-vue3'const route = useRoute()// Nginx 配置(location^~ /subAppUrl)一致
const subAppUrl= ref()watch(() => route.fullPath,(newPath) => {subAppUrl.value = newPath// url地址为: /subapp/、/sbuapp/system、/subapp/log...},{ immediate: true })</script>
http://www.xdnf.cn/news/882379.html

相关文章:

  • 机器学习与深度学习12-K近邻算法
  • C++虚函数表(虚表Virtual Table,简称vtable、VFT)(编译器为支持运行时多态(动态绑定)而自动生成的一种内部数据结构)虚函数指针vptr
  • 关于akka官方quickstart示例程序(scala)的记录
  • 【C++项目】负载均衡在线OJ系统-2
  • 解构与重构:PLM 系统如何从管理工具进化为创新操作系统?
  • 通过Chain Prompts方式将LLM的能力引入测试平台:正交实验测试用例生成
  • 多模态大语言模型arxiv论文略读(109)
  • 计算机基础知识(第四篇)
  • Apache Doris + MCP:Agent 时代的实时数据分析底座
  • Ntfs!ReadIndexBuffer函数分析之nt!CcGetVirtualAddress函数之nt!CcGetVacbMiss
  • 如何在电脑上轻松访问 iPhone 文件
  • 斐波那契数列------矩阵幂法
  • 【Python3教程】Python3基础篇之错误和异常
  • Python语法进阶篇 --- 封装、继承、多态、静态方法、类方法
  • 嵌入式学习Day33
  • 如何更快的提升项目的开发进度
  • 从 ClickHouse、Druid、Kylin 到 Doris:网易云音乐 PB 级实时分析平台降本增效
  • 【SSM】SpringBoot笔记2:整合Junit、MyBatis
  • XHR / Fetch / Axios 请求的取消请求与请求重试
  • JVM——如何打造一个类加载器?
  • NLP驱动网页数据分类与抽取实战
  • 「深度拆解」Spring Boot如何用DeepSeek重构MCP通信层?从线程模型到分布式推理的架构进化
  • 自动驾驶+人形机器人?亚马逊即将测试人形机器人送货
  • 元素 “cas:serviceResponse“ 的前缀 “cas“ 未绑定
  • 使用ReactNative加载Svga动画支持三端【Android/IOS/Harmony】
  • StarRocks
  • Spring Boot + OpenAI 构建基于RAG的智能问答系统
  • Java 抗量子算法:构建后量子时代的安全基石
  • 系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
  • 接IT方案编写(PPT/WORD)、业务架构设计、投标任务