为什么要 BFF

小程序前端直接调后端微服务,常见两个问题:一个页面要拼好几个接口、来回慢;鉴权散落在每个接口里,改一处漏一处。BFF 就是夹在小程序和后端服务中间的那一层,专门为小程序服务。

BFF 不是万能中间层。它只做「给小程序适配」的事,别把业务逻辑再往里堆,不然就成了第二个后端。

判断要不要 BFF,看一个信号就行:前端是不是要拼好几个接口、鉴权是不是到处重复。两个都中,就值得加这一层。

什么时候不该上?项目还很简单、前端就两三个人,硬加一层反而多了运维负担。规模到了再加不迟。

BFF 干的是「适配」,不是「代替后端做业务」。
本文核心知识点
  • 聚合把多个后端接口合并成一次请求。
  • 鉴权登录校验统一在网关做。
  • 限流保护后端,也防刷。
  • 降级下游挂了别让整页崩。
小程序 BFF 示意:蓝调渐变背景上居中网关节点向四周分发数据流的扁平科技插画
前端只管调 BFF,后端细节都收在这一层后面。

接口聚合:一次拿全

一个首页要拿 banner、分类、商品列表,前端原来发三个请求。BFF 里并行调这三个后端接口,合并成一个返回,前端一次就拿全了。

做法效果
前端直连多服务多次往返,慢
BFF 聚合一次返回,快
字段裁剪只要小程序用得上的字段
// BFF 一次并发拉多个后端,合并返回
const [banner, list] = await Promise.all([
  api.getBanner(), api.getGoods()
]);
return { banner, list };

聚合的时候顺便做字段裁剪。后端为了通用性,一个接口返回几十个字段,小程序其实只用其中几个。BFF 把用不上的字段剔掉,流量小、解析也快。

聚合也别贪多。一次聚合七八个后端接口,任何一个慢就拖垮整次请求。一般两三个最合适,多了就该重新拆。

鉴权:收在网关

登录态校验放在 BFF 这一层统一做,后端服务就不用每个接口都查一次 token。前端只跟 BFF 打交道,token 的事它自己处理。

// BFF 中间件先校验登录态,再放行
if (!checkToken(req.token)) return { code: 401 };

后端服务只信任 BFF 转过来的内部请求,外部直接打后端的口子要封掉。

token 刷新也在 BFF 里处理。前端只管发请求,token 快过期了 BFF 自己续,前端不用知道这套机制。

权限粒度也在网关控。不同身份的用户能调哪些接口,在 BFF 配好,后端只管老老实实出服务。

限流与降级

后端扛不住的时候,BFF 先拦一刀:限流,别把流量直接灌到下游。再做降级:某个商品服务挂了,首页先出 banner 和分类,别整页白屏。

  • 按用户、按接口设限流阈值。
  • 下游超时要有兜底数据。
  • 降级别悄悄,要打日志。

限流不是单纯挡人。对恶意刷接口的,限流是保护;对正常用户,降级是体验兜底。两个一起做,才既稳又不伤人。

降级要有预案。事先想好哪个服务挂了用什么兜底,别等挂了才现想,那时候手忙脚乱。

错误统一处理

错误码也在 BFF 里统一翻译。后端一百个错误码,前端只认 BFF 约定的那几个。这样后端怎么改错误码,前端都不受影响。

// 后端错误码映射成前端统一约定
return { code: 0, data, msg: ok ? "" : "系统繁忙" };

统一的好处是前端好处理,坏处是映射表要维护清楚,别越积越乱。

接口契约最好有个文档。BFF 给前端的返回长什么样写清楚,前后端对接省得每次来回问;契约定下来,两边都照它来,出问题也好对。