一、软件架构分层及作用
展示层:
- 负责用户界面交互,支持单页面(CSR-SPA)或多页面(SSR-MPA)渲染。
- 通过接口与接入层通信,获取数据并展示。
接入层:
- 路由分发请求,将不同业务导向BFF层的对应控制器。
BFF层(Backend For Frontend)
- 业务场景聚合层,包含控制器(处理请求)、环境配置、定时任务等模块。
- 核心职责:适配多端需求,聚合数据,减轻前端复杂度。
服务层:
- 提供标准化服务(如用户管理、支付等),实现核心逻辑复用。
数据层:
- 通过数据库、缓存、消息队列等组件,完成数据的持久化与读写操作。
二、BFF层的核心价值(参考文献:zhuanlan.zhihu.com/p/634498512…
BFF(Backend For Frontend)是一种架构设计模式,核心思想是为不同的前端客户端(如Web、移动端等)定制专用的后端服务,解决多端接口适配和数据聚合问题
- 多端适配:针对不同客户端(Web/移动端)定制数据结构和接口。
- 逻辑下沉:将数据聚合、错误处理等复杂逻辑从前端转移至BFF,提升前端性能。
- 微服务整合:聚合多个微服务调用,减少前端直接依赖的接口数量。
- 快速迭代:独立于后端服务更新,支持前端需求的敏捷开发。
三、Koa洋葱模型解析
Koa是一个基于Node.js的Web框架,洋葱模型是Koa的核心设计思想。用来构建Web应用,它比Express更轻量,中间件机制不同。
1. 洋葱模型,顾名思义就像一个洋葱,请求从外到内,响应从内到外,中间件按照洋葱的层级依次执行。
比如,假设有三个中间件A、B、C,请求从A的前半部分->B的前半部分->C的前半部分,响应从C的后半部分->B的后半部分->A的后半部分。这样的整个流程就像穿过洋葱一样,先一层层进入,再一层层退出。这样的设计好处是:可以在请求和响应的不同阶段,对请求和响应进行处理,比如:日志记录、权限校验、异常处理等。
2. 中间件在Koa中是怎么写的呢?
在Koa中,中间件函数通常是async函数,接收两个参数,ctx和next。当调用next()时,会暂停当前中间件的执行,将控制权交给下一个中间件。等到后面的中间件执行完了,再回到当前中间件继续执行后面的代码。这样,中间件的执行顺序就是洋葱模型。
举个例子,比如:
当请求进来时,执行顺序是1-start->2-start->3-start->3-end->2-end->1-end。这样看起来就像一个洋葱,请求先经过外层中间件的前半部分,进入内层,处理完再逆序执行后半部分。
这样的话。每个中间件都可以在请求处理前后插入逻辑,比如记录开始时间和结束时间,计算总耗时,记录日志等。
3. Koa是怎么实现这种洋葱模型的呢?
中间件的执行机制可能使用类似递归的方式,或者通过组合中间件的函数将这些中间件组合成一个执行链,使得每个中间件的next()指向下一个中间件。当调用next()时,实际上就是调用下一个中间件函数, 直到最后一个中间件执行完毕后,再逐层返回。这需要中间件函数返回Promise,或使用async/await来管理异步流程
4. 洋葱模型优势
- 统一逻辑处理:例如在请求开始时记录时间,结尾计算耗时。
- 灵活插入逻辑:中间件无需知道其他中间件存在,只需关注自身职责。
- 响应后操作:如清理资源、设置响应头等。
另外,洋葱模型和Express的中间件有什么不同?Express的中间件是线性的,每个中间件依次执行,没有这种先进后出的机制。 例如,Express中间件在处理完自己的逻辑后,可以传递给下一个中间件,但后续的中间件处理完毕后,不会返回到之前的中间件。也就是说,Express的中间件是顺序执行, 而Koa的是洋葱式执行。这使得在Koa中处理响应后的逻辑更为方便,比如记录响应时间,因为可以在中间件的前后部分分别记录开始和结束时间,然后计算差值
5. 总结
Koa的洋葱模型是指中间件的执行顺序类似于洋葱的结构,请求从外到内穿过所有中间件的前半部分,然后从内到外穿过中间件的后半部分。 这种机制通过async/await和next()函数实现,确保每个中间件在调用next()时暂停,等待后续中间件处理完毕后再继续执行。这种模型让处理请求前后的逻辑更加灵活和统一
四、实现服务引擎
- 通过 BFF 架构设计模式基于 Koa 实现服务端内核,应用于接入层、业务层、服务层等。遵循约定大于配置设计范式在架构约定目录,通过服务引擎各系列 loader 解析对应文件加载至运行时内存中,从而实现整体框架
1. 架构约定的目录
- app.router/** :用于配置URL路由规则
- app.router-schema/** :遵循JSON Schema模式定义数据结构
- app.controller/** :用于解析用户的输入,处理后返回相应的结果
- app.service/** :用于编写业务逻辑层
- app.middleware/** :用于编写中间件
- app.public/** :用于放静态资源
- app.extend/** : 用于框架的扩展
- middleware.js: 全局中间件,注册于服务引擎中
2. 服务引擎约定目录
- loader: 内核解析器
- loader.router:解析app.router下所有js文件,加载到KoaRouter下
- loader.router-schema:通过JSON Schema和ajv对API规则进行约束
- loader.controller:解析app.controller下所有js文件,可通过 'app.controllers.目录.文件' 访问
- loader.service:解析app.service下所有js文件,可通过 'app.service.目录.文件' 访问
- loader.middleware:解析app.middleware下所有js文件,可通过 'app.middleware.目录.文件' 访问
- loader.extend:解析app.extend下所有js文件,可通过 'app.extend.目录.文件' 访问
- loader.config:配置区分 本地/测试/生产, 通过 env 环境读取不同文件配置 env.config
- env.js: 环境配置文件
- index.js:启动文件。包含初始化环境配置、加载loader各个解析器、注册全局中间件、注册路由、启动服务功能等
2.1 loader实现
代码:loader.config
代码:loader.router
代码:loader.router-schema
代码:loader.middleware
代码:loader.controller
代码:loader.service
代码:loader.extend
代码:env
代码:index