微前端 - 对外只开放一个端口
问题
按原来的微前端部署形式,需要对外开放N(子系统个数)+1(主应用)个端口,存在网络安全的问题。
注意:此处不考虑https的问题,如需考虑,参考http即可。
目标
- 1、减少对外开放的端口
- 2、保证子系统能独立更新部署和访问
方案
为了保证子系统仍然是独立的,那么每个子系统必定对应一个NGINX(一个端口),但是此端口可以考虑不对外部网络开放,通过主应用的NGINX进行内部跳转。
步骤
一、处理主应用
改
registerMicroApps(
[
{
name: 'SubSystem',
entry: '//IP:PORT',
container: '#subContainer',
activeRule: '/micro/sub-system'
}
],
{
// 其实挂载子系统的速度很快,loading应该做到各个子系统中去。
beforeLoad: (app) => { // 子应用加载前
console.log('beforeLoad 子应用加载前')
},
afterMount: async (app) => { // 子应用完成加载后
console.log('afterMount 子应用完成加载后')
},
beforeMount: (app) => {
// 每次加载子系统都执行
}
})
为
registerMicroApps(
[
{
name: 'SubSystem',
entry: '/micro-system/',
container: '#subContainer',
activeRule: '/micro/sub-system'
}
],
{
// 其实挂载子系统的速度很快,loading应该做到各个子系统中去。
beforeLoad: (app) => { // 子应用加载前
console.log('beforeLoad 子应用加载前')
},
afterMount: async (app) => { // 子应用完成加载后
console.log('afterMount 子应用完成加载后')
},
beforeMount: (app) => {
// 每次加载子系统都执行
}
})
将原本entry: '//IP:PORT'
,子系统入口跳转至子系统的IP和端口配置,改为entry: '/micro-system/'
,跳转至/micro-system/通过NGINX去拦截跳转内部服务器IP和端口。
二、处理子系统
- 通过主应用访问子应用,加载子应用js资源
http://主应用IP:主应用端口/micro-system/js/chunk-vendors.********.js
- 通过NGINX去拦截跳转内部子应用服务器IP和端口
http://子应用IP:子应用端口/micro-system/js/chunk-vendors.********.js
如果子应用不做任何改动,是访问不到资源的。
方案1,行不通
将子应用拦截/micro-system/在转发重写URL时去掉,然而测试现象是加载冲突,无法正确转发加载到资源。
通过F12查看,资源好像是访问到9000(主应用端口)下的了。
方案2,可行
在不重写去掉/micro-system/的前提下,资源能正常访问,则需给子系统所有资源路径加上前缀。
2.1、vue.config.js打包配置文件
追加publicPath属性:
publicPath: '/micro-system/',
该配置的意思是,子系统打包后的所有资源路径前缀加上/micro-system/。
2.2、qiankun的子应用配置文件
改
export const render = (props = {}) => {
const { container } = props
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/micro/sub-system/' : '/',
mode: 'history',
routes
})
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount(container ? container.querySelector('#app') : '#app')
}
为
export const render = (props = {}) => {
const { container } = props
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/micro/sub-system/' : '/micro-system/',
mode: 'history',
routes
})
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount(container ? container.querySelector('#app') : '#app')
}
在不是通过主应用访问时,即单独访问子系统时,为路由的base追加/micro-system/。
因为vue.config.js的配置,打包后的子系统资源前缀都加上了/micro-system/,此处访问资源也需要加上不然无法正确获取资源。
三、本地部署测试
3.1、主应用需要添加拦截跳转
proxy: {
'/micro-system/': {
target: 'http://localhost:9001/',
changeOrigin: false,
secure: false
},
走主应用访问时资源,通过/micro-system/拦截,跳转子系统部署的IP和端口,此IP和端口可以不对外网开放。
可参考后台接口请求的拦截跳转。
资源加载:
加载效果:
3.2、子系统无需修改
但需要注意的是,访问的时候必须在端口后追加/micro-system/。
- 原来访问地址:
http://localhost:9001/login
- 现在访问地址:
http://localhost:9000/micro-system/login
(通过主应用端口访问子系统)http://localhost:9001/micro-system/login
(直接访问子系统)
此时,你会发现所有的资源访问后面都多了/micro-system/。
四、服务器部署测试
4.1、主应用NGINX追加子系统拦截
location /micro-system/ {
proxy_pass http://IP:PORT/micro-system/;
proxy_set_header Host $host:$server_port;
}
走主应用访问时资源,通过/micro-system/拦截,跳转子系统部署的IP和端口,此IP和端口可以不对外网开放。
可参考后台接口请求的拦截跳转。
注意:原来的~*
拦截(如果有的话)需要去掉,不然子系统的资源会被抢先拦截。
4.2、子系统NGINX拦截配置如下
location /micro-system/ {
try_files $uri $uri/ /micro-system/index.html;
alias /usr/share/nginx/html/;
index index.html index.htm;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
注意:
- a)、原来的
location /
拦截和~*
拦截(如果有的话)可以去掉了,因为所有的资源都在/micro-system/下。 - b)、本案例是通过docker容器管理NGINX的,在docker配置中,有将实际的dist包文件映射到/usr/share/nginx/html/。
- ./bpg-sub-system/web/dist:/usr/share/nginx/html
其实只需要将alias别名指向子系统dist包的位置即可。
结论
- 如果子应用部署的服务器端口,提供对外访问:
那么可以直接访问,只需要在端口后追加子系统拦截标识,即公共路径publicPath的配置即可。 - 如果子应用部署的服务器端口,不对外提供访问:
那么可以通过访问主应用的IP和端口,追加子系统拦截标识,同样可以通过NGINX转发的方式加载资源。
(类比接口调用,通常后台接口的服务器是不开放对外直接访问的,需要通过NGINX转发。)
此时,只需要对外提供主应用的端口,本案例是9000即可。
当然了如果有HTTPS那就再加一个。