做后台项目时,前端页面经常要和多个接口打交道。有的接口返回数据不能直接用于展示,有的页面需要组合几份数据。如果这些处理都散在页面里,后面维护起来会比较麻烦。
这里整理一下 elpis-core 里的 BFF 内核思路:基于 Koa 启动服务,按照目录约定加载配置、服务、控制器、中间件和路由,把一些通用的接入逻辑收在一起。
BFF 放在哪里
BFF 可以放在前端页面和后端服务之间,根据页面需要做接口聚合、数据转换或接口适配。它不是所有项目都必须有,也不意味着每一个 BFF 都实现了这些能力,要看实际业务需要。
一个请求大致会经过下面几层:
1 | 前端页面 → 路由和中间件 → Controller → Service → 数据库或其他服务 |
路由负责把请求分发到对应处理方法;Controller 处理请求和响应;Service 放可复用的业务或数据访问逻辑。鉴权、日志、错误处理等通用逻辑则可以放在中间件里。
目录怎么划分
1 | app/ |
目录约定的好处是查问题时比较容易定位。比如要看某个接口的入参,就可以先找对应的 router-schema;想知道请求最终做了什么,再往 controller 和 service 里看。
启动和加载
核心启动流程可以拆成几步:创建 Koa 实例,设置工作目录和环境,再依次加载配置、扩展、服务、控制器、参数规则、中间件和路由,最后监听端口。下面是简化后的流程示意:
1 | function start(options = {}) { |
这里的 loadConfig 等函数名只是为了说明流程,实际代码会拆到不同的 loader 文件中。加载顺序也有关系:例如路由要引用 controller,通常就需要先完成 controller 的加载。
Koa 的中间件执行顺序也值得注意:请求按注册顺序进入,遇到 await next() 后继续往下,后续中间件执行完再返回。因此错误捕获、日志和鉴权放在哪里,会直接影响它们能处理到什么。
一些需要注意的地方
目录自动加载能减少重复注册,但也增加了对命名和加载顺序的依赖。文件命名不符合约定、模块导出不符合预期,或者依赖的模块还没加载,都可能让问题变得不容易排查。启动日志和明确的错误提示就很有用了。
另外,BFF 有接口聚合和适配的空间,不代表所有接口都已经聚合了多个后端。实际介绍项目时,还是要结合具体接口的实现来讲。