了解前端后端 (BFF) 模式:简单指南
在微服务架构中,我们的系统被分解为数十个小型的、集中的服务,例如用户服务、订单服务和产品服务。
但是,在向用户显示此信息时,不同的设备有非常不同的需求。高速台式计算机上的网络浏览器需要一个包含表格、侧边栏和图表的丰富仪表板。慢速蜂窝网络上的移动应用程序需要简单、轻量级的布局来节省带宽和电池。智能手表应用程序可能只需要一行文本。
如果所有这些前端都查询完全相同的后端 API,则必须有人做出妥协。要么移动应用程序被迫下载大量无用的数据,要么网络应用程序被迫发出数十个单独的网络请求来获取所需的所有内容。
这正是 后端为前端 (BFF) 模式 解决的问题。在本指南中,我们将用简单的语言解释此模式,查看现实世界的类比,将其与标准 API 网关进行比较,并逐步完成实际的代码实现。
现实世界的类比:餐厅菜单
想象一家餐厅为三种截然不同类型的食客提供服务:
- 一位美食评论家想要一份完整的 5 道菜品尝菜单以及详细的成分列表。
- 忙碌的通勤者想要在火车上吃一份预先包装好的快餐。
- 一个孩子想要一份简单的儿童餐,份量小,没有辛辣的成分。
如果餐厅只有一份菜单详细列出所有三个选项,那就会让人不知所措。通勤者会浪费时间阅读 5 道菜的食谱,而孩子的父母则很难找到简单的食物选择。
相反,餐厅打印三个自定义菜单:品尝菜单、快速外带菜单和儿童菜单。
每个菜单都来自同一个厨房(微服务),但专门针对该客户(客户端)设置选项的格式和大小。
在这种情况下:
- 厨房代表您的微服务(用户、目录、付款)。
- 自定义菜单是您的BFF(Web BFF、移动 BFF、观看 BFF)。
- 食客是您的前端(桌面浏览器、移动应用程序、智能手表)。
问题:“一刀切”的 API
当微服务第一次流行时,许多团队构建了一个单一的、共享的 API 网关来处理所有前端客户端:
虽然单个入口点很好,但共享 API 引入了几个扩展瓶颈:
- 移动设备的有效负载膨胀:桌面 Web 应用程序需要用户的订单历史记录、帐单地址、个人资料图片和忠诚度积分。移动应用程序只需显示“最后订单:已发货”。通过共享 API,移动应用程序会下载整个配置文件有效负载,从而浪费宝贵的数据并减慢加载时间。
- API 瓶颈:单个团队成为共享网关的瓶颈。如果iOS团队想要改变一个小的布局字段,他们必须等待共享网关团队部署新版本,从而减慢开发周期。
- 不同的安全需求:Web 浏览器可能需要基于 cookie 的会话来防止跨站点脚本 (XSS),而移动应用程序更喜欢基于令牌的 OAuth 标头。在单个服务器中处理这两者会产生复杂、混乱的代码。
解决方案:BFF 模式
BFF 模式提倡为 每个前端应用程序构建一个专用后端服务器,而不是为所有设备创建一个巨型网关。
您将拥有:
- Web BFF:处理来自桌面浏览器的请求。它汇总了完整的配置文件、产品目录和详细的结帐信息。
- Mobile BFF:处理来自 iOS 和 Android 应用程序的请求。它聚合数据,过滤掉不必要的字段,并压缩最终响应以确保快速性能。
API Gateway 与 BFF:有什么区别?
人们很容易混淆这两种模式,因为它们都位于客户端和微服务之间。这是区别:
| 特色 | 通用API网关 | 前端后端 (BFF) |
|---|---|---|
| 网关数量 | 通常一个用于整个系统。 | 多个(每种类型的客户端设备一个)。 |
| 责任 | 高级路由、速率限制和全局安全。 | 聚合数据并为特定前端定制有效负载。 |
| 所有权 | 由专门的后端/平台基础设施团队管理。 | 由构建相应应用程序的前端团队管理。 |
| 定制 | 低的。更改会影响所有客户。 | 高的。更改仅影响一个客户端应用程序。 |
实际实现 (Node.js/Express)
为了了解它在实践中是如何工作的,让我们编写一个简单的 Node.js 示例。
想象一下我们有两个内部运行的微服务:
- 用户服务(返回基本的用户个人资料信息)
- 订单服务(返回包含完整详细信息的订单列表)
我们希望构建一个 Web BFF 和 Mobile BFF 来以不同的方式为我们的桌面网站和移动应用程序提供服务。
1. 共享微服务模拟
首先,这是我们两个底层微服务的模拟数据:
// Internal User Service Response
const userProfile = {
id: 42,
username: "dev_coder",
email: "coder@ghaznix.com",
avatarUrl: "https://ghaznix.com/avatars/42.png",
preferences: { theme: "light", newsletter: true }
};
// Internal Order Service Response
const orderHistory = [
{ id: "ORD-99", date: "2026-06-25", items: ["Laptop", "Mouse"], status: "Shipped", tax: 15.00, total: 1215.00 },
{ id: "ORD-88", date: "2026-05-12", items: ["Keyboard"], status: "Delivered", tax: 5.00, total: 105.00 }
];
2. Web BFF(返回完整详细的有效负载)
Web BFF 聚合了所有字段,因为桌面屏幕有足够的空间来显示它们:
const express = require('express');
const webBff = express();
webBff.get('/dashboard', (req, res) => {
// Web needs everything: profile + full order details + settings
const responsePayload = {
user: {
username: userProfile.username,
email: userProfile.email,
avatar: userProfile.avatarUrl,
theme: userProfile.preferences.theme
},
orders: orderHistory // Send all order details, taxes, and items
};
res.json(responsePayload);
});
webBff.listen(3001, () => console.log('Web BFF running on port 3001'));
3. 移动 BFF(返回最小化聚合有效负载)
Mobile BFF 会过滤掉不需要的字段(例如电子邮件、设置和税费)并聚合订单项以节省带宽:
const express = require('express');
const mobileBff = express();
mobileBff.get('/dashboard', (req, res) => {
// Mobile only wants: username, avatar, and summary of the latest order
const latestOrder = orderHistory[0];
const responsePayload = {
user: {
username: userProfile.username,
avatar: userProfile.avatarUrl
},
latestOrderStatus: {
orderId: latestOrder.id,
status: latestOrder.status,
date: latestOrder.date,
itemCount: latestOrder.items.length // Send count instead of array list
}
};
res.json(responsePayload);
});
mobileBff.listen(3002, () => console.log('Mobile BFF running on port 3002'));
有效负载大小比较
- Web BFF 响应大小:包含嵌套配置、首选项、完整订单列表、税费、项目等(约 400 字节)。
- 移动 BFF 响应大小:仅包含代表基本要素的 6 个键值对。 (大约 120 字节 — 网络大小减少 70%!)。
BFF 模式的优点和缺点
BFF 模式虽然非常有效,但也有其缺点:
| 优势(专业版) | 缺点(缺点) |
|---|---|
| 优化客户端性能:客户端仅加载他们需要的确切数据,减少电池消耗和内存使用。 | 代码重复:您最终可能会在多个 BFF 代码库中编写类似的数据获取逻辑。 |
| 更快的发布周期:移动前端团队可以更新其 BFF 服务器,而无需与 Web 开发人员协调。 | 增加服务器数量:您现在必须部署和管理多个 BFF 服务,而不是管理一个 API 网关。 |
| 简化的前端代码:客户端不需要处理复杂的排序、过滤或合并逻辑;它只是显示它收到的 JSON。 | 安全管理:SSL/TLS 认证、速率限制规则和防火墙必须跨多个网关进行管理。 |
## 结论
前端后端 (BFF) 模式是一种功能强大的架构,适用于服务多种客户端类型(例如 Web、移动和 IoT 设备)的系统。通过为每个特定前端创建定制网关,您可以解耦客户端开发、最小化有效负载大小,并提供更快、响应更灵敏的用户体验。
如果您的系统只有一个 Web 应用程序,则共享 API 网关就足够了。但是,当您开始与 Web 应用程序一起构建移动应用程序或专用设备体验时,实现 BFF 是保持前端和后端架构清洁、优化和独立的最佳方式。