返回 Android
Android
13 分钟阅读

Backend For Frontend

BFF 模式的架构定位、适用边界,以及团队为何常在前端聚合与专用 BFF 之间做出不同选择

在微服务与领域驱动设计(DDD)被广泛采用的今天,后端接口往往按业务域而非用户场景来划分。一个完整的页面或交互流程,常常需要客户端依次调用多个领域服务——用户、订单、库存、营销权益等。此时团队面临一个架构抉择:由客户端自行聚合多个 REST/gRPC 调用,还是引入一层 Backend For Frontend(BFF),为特定前端形态提供场景化的聚合接口。

BFF 并非新概念。Sam Newman 在《Building Microservices》中将其定义为:面向特定客户端类型(Web、Mobile、Admin 等)的专用后端层,负责协议转换、数据裁剪、多服务编排,以及将领域模型映射为前端可直接消费的场景模型。它与 API Gateway 的职责不同:Gateway 侧重路由、限流、鉴权等横切能力;BFF 侧重体验层的数据编排与契约适配

BFF 架构总览:客户端 → 专用 BFF 层 → API Gateway → 领域微服务,以及与客户端聚合模式的对比


一、两种路径的本质差异

维度客户端聚合(Client-side Aggregation)BFF 聚合(Server-side Aggregation)
编排位置前端 Repository / ViewModel 层独立 BFF 服务
接口契约前端直接依赖多个领域 API前端只依赖面向场景的 BFF 契约
变更响应UI 迭代时前端自行调整拼装逻辑UI 迭代时 BFF 调整,领域服务保持稳定
网络开销多次往返(RTT 累加),移动端尤为明显单次请求,服务端内网并行调用
安全边界更多领域服务需暴露至客户端可达层领域服务可收敛在内网,BFF 作为唯一出口

两种路径没有绝对优劣,差异在于成本转移:客户端聚合把编排复杂度、耦合风险和网络开销转移给了前端;BFF 则把这些成本集中到一个需要持续维护的服务层。


二、选择客户端聚合的常见理由

1. 交付成本与组织边界

在资源有限或 MVP 阶段,让前端通过 async/await / Promise.all 并行调用多个接口,可以绕过后端排期,由前端团队独立完成页面交付。对于小团队而言,少一层服务意味着少一份部署、监控、On-call 与版本协调成本。

2. 迭代灵活性

领域 API 相对稳定时,UI 层的字段组合、排序、过滤逻辑可以在前端快速调整,无需等待后端改接口、走发布流程。这在 A/B 测试频繁、页面结构变化快的早期产品中有一定优势。

3. 早期性能可接受

用户规模有限、页面并发请求数可控时,多几次 HTTP 往返往往不构成瓶颈。移动端在 Wi-Fi 环境下,2~3 次并行请求的体感延迟尚可接受。

4. 避免 BFF 的维护负担

BFF 本质上是场景驱动的 API 层,会随前端页面迭代而频繁变更。团队若缺乏 BFF 的治理经验,容易将其演化为"第二个前端"——接口数量膨胀、与多个领域服务形成网状依赖、变更牵一发而动全身。


三、客户端聚合的结构性问题

当产品复杂度上升,上述"低成本"路径会暴露出架构层面的隐患。

1. 客户端与领域模型的强耦合

前端必须理解每个微服务的接口语义、分页策略、错误码约定和数据模型。领域服务一旦重构(字段迁移、接口拆分、版本升级),所有客户端(Web、iOS、Android、小程序)需同步修改,重复劳动且容易遗漏,形成"分布式单体"的反模式。

2. 网络性能与移动端约束

即便客户端并行发起请求,仍受限于最慢请求的 RTT 以及移动网络的连接建立开销。一个首页若需 5~8 个领域调用,在 4G 弱网下的首屏时间往往不可接受。服务端内网调用延迟通常在亚毫秒级,BFF 在服务端并行编排后一次返回,网络开销从 O(n) 降为 O(1)。

3. 安全攻击面扩大

客户端直连多个领域服务,意味着这些服务的 API 需通过网关暴露至公网。攻击者可通过抓包还原内部 API 结构,增加接口滥用与越权访问的风险。BFF 作为唯一对外出口,可在服务端完成鉴权、字段脱敏与权限裁剪。

4. 多端重复实现

Web、iOS、Android、HarmonyOS 对同一业务场景的聚合逻辑、容错策略、缓存策略往往各自实现一遍。逻辑漂移导致跨端行为不一致——同一页面在不同端展示不同数据或错误处理方式不同,增加 QA 与客诉成本。


四、实践中的选型规律

倾向客户端聚合

  • 团队规模小,前端可独立交付
  • 产品处于 MVP 或验证期,页面结构尚未稳定
  • 微服务数量少,单次页面所需接口 ≤ 2~3 个
  • 暂无多端并行开发的重复成本

倾向引入 BFF

  • 多端共存(Web + iOS + Android + 小程序),聚合逻辑需统一
  • 微服务规模较大,单页面涉及 4 个以上领域调用
  • 对首屏延迟、弱网体验有明确 SLA
  • 安全合规要求领域服务不直接暴露至客户端
  • 团队具备 BFF 层的持续维护能力(人力、规范、监控)

五、团队决策中的非技术因素

架构选型很少纯粹由技术优劣决定。BFF 在不少团队中被搁置或推迟,常见原因如下。

1. 优先级与资源分配

后端排期通常优先保障核心业务域(订单、支付、库存等)的稳定性与功能交付。BFF 属于体验优化层,对营收类 KPI 无直接贡献,在 OKR 或 Sprint 规划中容易被排在 backlog 末尾。

2. 职责边界与 Ownership 争议

领域 API 遵循领域驱动的建模方式;前端期望的是场景驱动的聚合契约。若缺少 BFF 这一中间层来承接"体验层契约",矛盾便落在前端与后端之间:前端认为"你应该给我一个能直接用的接口",后端认为"这是你们的数据拼装,不属于领域服务的职责"。

BFF 引入后,前端需求变更会转化为 BFF 接口变更,后端团队需承担额外的维护与联调成本。在缺乏明确 Ownership 约定的组织中,这一层往往无人认领。

3. 工程经验与基础设施缺口

许多团队缺乏 BFF 或 GraphQL 的落地经验,对以下问题没有共识:

  • BFF 部署在 Gateway 之后还是之前?
  • 鉴权 Token 如何在 BFF 与下游服务间传递?
  • 缓存策略放在哪一层?BFF 响应缓存 vs 领域服务缓存如何协调?
  • BFF 与领域服务的超时、熔断、降级如何配置?

在缺少最佳实践与平台支持的情况下,维持"Gateway + 微服务 + 前端拼装"的现有模式,是风险更低的默认选择。

4. 短期交付 vs 长期债务

客户端聚合在短期不影响上线节奏,性能与维护问题往往在业务复杂度或团队规模达到阈值后才集中爆发。许多团队采取"能跑就行"的策略,直到多端重复、接口变更牵一发动全身,才被迫引入 BFF 或 GraphQL 进行重构——此时迁移成本已显著高于早期引入。


六、落地建议

若决定引入 BFF,可参考以下原则,避免将其演化为难以维护的"大泥球"。

  1. 按客户端形态拆分,而非按页面拆分:Web BFF、Mobile BFF、Admin BFF 各维护一套场景契约,避免单一 BFF 承载所有端的差异逻辑。
  2. BFF 只做编排与适配,不写业务逻辑:领域规则仍归属领域服务,BFF 不包含订单计算、库存扣减等核心业务。
  3. 明确 Ownership:通常由前端团队主导 BFF 契约设计,后端或平台团队提供部署与治理支持;或由专职的体验层团队维护。
  4. 与 API Gateway 分工清晰:Gateway 管路由、限流、鉴权;BFF 管场景聚合与模型映射。
  5. 评估 GraphQL 作为替代方案:当客户端对字段裁剪、按需加载的需求强烈时,GraphQL 可在一定程度上替代 REST 风格的 BFF,但需权衡 Schema 治理与 N+1 查询等复杂度。

总结

客户端 async/await 聚合适合快速验证、资源敏感、微服务规模有限的阶段;BFF 适合多端并行、领域服务较多、对体验与安全有明确要求的成熟产品。

两者之间的选择,本质是在交付速度架构可持续性之间做权衡。关键不在于"要不要 BFF"这一是非题,而在于团队是否识别到了客户端聚合的复杂度阈值——当重复实现、网络开销、耦合变更的成本超过 BFF 的维护成本时,引入专用体验层通常是更理性的架构演进方向。