随着微服务架构越来越复杂,前端需要和越来越多的后端服务交互,为了解决前端的复杂性问题,提出了 BFF 架构。原文: What is a BFF? And how to build one?
现在谁还会构建单体服务?微服务才是正确的选择!但这不是一个容易的选择,会引入各种各样复杂性。比方说,假设后端有若干对前端隐藏的微服务,那对于 SPA 或移动应用来说会产生多少额外的开销?
通用 API 可能会要求使用者聚合、过滤各个端点的响应,以便为终端用户提供有用的内容。
如何维护由多个微前端连接的一系列微服务架构?微服务承诺让应用更加敏捷,可以随意创建新的微服务,并在需要时拆除旧的服务,但这将对前端产生什么样的影响?
因此,为了解决这些问题,现在出现了另一种模式: The Backend For Frontend。这一概念正如所期望的那样: 每个前端都有一个后端,充当前端应用程序(SPA/Mobile)和域服务之间的接口,是一个用于查询下游服务并将响应转换为专门针对特定前端的单一格式化响应的 API。从示意图上看,微服务环境中的 BFF 可能是这样的:
BFF+微服务架构
BFF 的概念最早是由SoundCloud提出的。
BFF,身份验证,以及无 cookie 时代
你可能想知道这与本文有什么关系,在没有 cookie 的时代,BFF 模式比上图中显示的要复杂一些。
在许多情况下,下游服务通常需要基于(访问)令牌验证身份,BFF 需要在向下游转发的请求中包含这些令牌。
在 SPA 中存储 access_token 是一种常见的实践。令牌被包含在请求中,API 就能够知道是谁在执行请求。但是通常来说,这种方法会有一个问题。当令牌过期(通常是一小时),SPA 一般会静默刷新令牌。这种机制是基于第三方 cookie 的,而这些cookie很快就没法再用了。因此,2024 年以后就没法再用静默刷新。
考虑到这一点,BFF 无论如何都需要用户的 access_token,这使得对 SPA 进行身份验证成了一件怪事。对于 BFF, SPA 不应该直接与下游服务通信,然而因为需要身份验证,BFF 总是需要在下游请求中包含 access_token。因此,从这个角度来看,让最终用户只针对 BFF 进行身份验证更有意义。这消除了通过 SPA 更新令牌的需要(并且根本不需要在 SPA 中拥有令牌)。
下图展示了 BFF 和微服务的身份验证过程:
BFF 认证时序图
要使其工作,BFF 和 SPA 必须托管在相同的 URL 上,这样,当 SPA 向 BFF 发起 HTTP 请求时,HTTP 请求将包含 cookie,而 BFF 需要通过这些 cookie 来获取用户上下文(access_token)并将其转发到下游。
如何实现?
BFF 是前端的一部分,减少了对下游服务的 API 请求数量,并减少了前端到 BFF 之间传输的数据量。BFF 通过转换 API 请求并转发到一个或多个通用 API 来实现这一点,同时支持聚合响应并将其转换为仅包含前端所需内容的响应。
这仍然是一个相当宽泛的定义,应该如何实现呢?Cam Jackson 给出了一个更复杂的定义:
图片来源: https://martinfowler.com/articles/micro-frontends.html
根据这一定义,有几种方法符合要求,分别支持带有专用存储的成熟 API 服务以及能够转发请求并在需要时转换响应的第三方实现。
选择 1: Duende
不必自己实现,有几个项目提供了免费的现成解决方案。例如,IdentityServer 的维护者提供名为 Duende 的解决方案:https://docs.duendesoftware.com/identityserver/v5/bff (实现示例如下:https://docs.duendesoftware.com/identityserver/v5/samples/bff)
通过将 Duende 纳入项目,可以作为一个很好的开始。它实现了身份验证机制,并且可以配置为将请求转发到下游 API。
选择 2: 自己实现
考虑到 BFF 的非泛型性质,自己构建是有意义的。你需要做以下事情:
创建一个 API 项目。
实现身份验证,使用 OpenId 连接授权代码流(基于 PKCE)并将访问令牌存储在安全 cookie 中。
创建 API 端点并从 cookie 中获取令牌,用令牌调用要使用的服务的端点。
必要时转换响应。
创建 SPA 并将其托管在同一个站点/项目上。
通过前面创建的 API 端点发布 SPI。
就这些……
总结
微服务和微前端之间的通信可能并不高效,微服务可能提供了通用 API(如果有的话),所以前端可能需要调用多个微服务来完成工作,并从响应中过滤需要显示的信息。结果,前端变得很复杂。
此外,当服务变得更小时,就需要调用更多的服务来完成工作。多个前端都需要调用所有这些对象的方式可能并不可取,使得维护更加困难。
为了解决这些问题,SoundCloud 在架构中引入了一个额外的层,将 API 作为前端的一部分,充当前端和下游服务之间的接口,聚合响应或/和过滤有效响应。
这个概念就被称为 BFF(Backend For Frontend)。
- END -
往期回顾
◆5 分钟搞懂 Web3 架构
◆一支不足百人的团队创造了 ChatGPT :90 后挑大梁,应届生 11 人,华人抢眼
◆JVM碰到问题,这几个工具不能少
◆聊聊流程引擎的架构设计
◆存储拆分后,如何解决唯一主键问题?
◆微服务架构中多级缓存设计
◆5个开源且简单实用的Code Review工具
◆大厂怎么做Code Review?
技术交流,请加微信: jiagou6688 ,备注:Java,拉你进架构群