译者按
译者在学习BFF时,有幸读到了作者古川陽介写的这一系列文章,收获颇多。由于在网上没有找到类似的中文资料,所以想将其翻译为中文,分享给小伙伴们。
前言
在本系列“微服务/API时代的前端开发”中,我们将介绍当前备受关注的BFF(Backends For Frontends)。这一篇,我们将介绍 BFF 的五个典型使用案例。
在之前的[微服务/API时代的前端开发] BFF超入门--Netflix、Twitter、Recruit选择BFF的理由一文中,我介绍了BFF的概要和案例。
可能很难理解 BFF 是做什么的,简单地说,API 服务器负责业务领域的逻辑部分,而 BFF 是支持用户界面的服务器。如果Web应用可以使用领域逻辑简单地创建,那么就不需要BFF。但是在微服务/API时代,前端开发越来越需要“汇总API”和“进行服务端渲染”。(如果想了解更多关于领域驱动设计DDD,可以参看笔者的DDD专栏)
因此,这一次,我们将介绍 BFF 的五个典型用例。
- API Gateway
- 服务器端渲染(Server Side Rendering)
- 会话管理(Session Management)
- 文件上传
- WebSocket、Server Sent Events、Long Polling
BFF的使用案例可以大致分为两类,像Server Side Rendering一样替代客户端的一些功能的,或者作为后端API服务器和客户端之间的中介并简化API实现。
然而,它是一种对 BFF 做任何事情的反模式。 BFF 用于本文介绍的用例,但同样重要的是不要通过更改后端 API 服务器端或客户端的实现来使 BFF 尽可能厚。下次我会更多地讨论反模式。
API Gateway
API Gateway,顾名思义就是指向API的入口。作为后端API的桥梁,将多个API聚合为一个,或者将API的响应结果翻译为客户端需要的格式。
API Gateway 主要有以下功能:
- 集成后端API的API Aggregation
- 为客户翻译API数据的API Translation
- 将API的查询结果保存在缓存中的API Cache
- 过滤API响应中的信息来减少数据大小的API Filter
在本文中,我们将把 API Aggregation 作为一个典型的功能来解释。
使用微服务构建客户端时,一个功能可能由多个API(多个微服务)实现。例如“显示页面时,从日记列表API获取日记的列表信息,同时从评论列表API获取多个评论”。在这种情况下,需要同时请求多个 API。
但是,浏览器可以同时发出请求的次数是有限制的。使用 HTTP / 1.1,一次最多只能建立 6 条连接。即使你想批量请求 API,也会收到此限制。此外,每次发出请求时检查会话并建立 TCP 连接,会增加连接服务器的成本。
BFF 可以将此 API 合并为一个请求。这样就不受浏览器请求数量的限制。此外,由于只需要进行一次会话检查和 TCP 连接,因此可以更高效的访问网络资源。
API网关的其他功能请参考“API Gateway Pattern”。
服务器端渲染(Server Side Rendering)
从服务器接收 JSON 并在客户端构建 HTML 称为“客户端渲染”,而在客户端和服务器上使用公共代码构建 HTML 称为服务器端渲染(SSR)。
现在的Web应用不仅返回HTML,很多情况下还会将JSON作为数据格式,在客户端构建HTML,但还是有很多情况需要服务端来渲染HTML,尤其是“搜索引擎优化”和“加速初期显示”的时候。
搜索引擎优化
以谷歌为代表的搜索引擎爬虫具有执行JavaScript的功能,通过Client Side Rendering构建HTML后可以创建索引。然而,搜索引擎爬虫也不是完美的,JavaScript 的执行并不总是有效的。有些爬虫不支持新的 JavaScript 语法,如果是一个无限滚动的网页,只在滚动页面时刷新内容,由于爬虫不会滚动页面,所以获取不到滚动后刷新的内容。
对于搜索引擎优化,建议从一开始就用HTML构建想要放入搜索引擎的信息(参考:Google SEO 建议使用JS框架的网站进行预渲染)。
加速初期显示
另外,在Client Side Rendering中,需要先加载JavaScript来构建HTML,因此会消耗更多时间。在Server Side Rendering中,HTML从一开始就存在,所以初期显示会更快。
通用应用(Universal Application)
Server Side Rendering一般会采用在Client Side和Server Side都能运行的通用机制来构建HTML。如果单纯只考虑实现,就可能会在客户端和服务器端同时构建View,很容易导致重复开发。为了避免这种情况,需要在服务器端和客户端使用相同的机制(在 Web 应用的情况下为 JavaScript)进行渲染。这种机制被称为“通用应用”。
最近有很多案例,在客户端和服务器端都采用了React.js或Vue.js进行渲染。 React.js 有一个“Next.js”框架,可以实现服务端渲染。在 Vue.js 中,使用“Nuxt.js”等框架也可以相对容易地实现服务器端渲染。
会话管理(Session Management)
会话管理是保留用户信息的功能。
这里的会话管理会话是指客户端和服务器之间进行双向通信时的用户会话。为了管理用户会话,服务器需要知道客户端是谁。在许多情况下,我们会向访问用户提供 cookie 并管理与 cookie 相关联的“用户信息”。用户信息包括用户ID、姓名、头像和“是否已登录”等等。
这些用户信息被频繁访问,需要高速存取。因此,它往往存储在Redis或memcached等高速缓存中。如果BFF实现了从高速数据存储中检索“谁是客户端”等信息的作用,后端服务器就不需要维护用户的状态,API服务器的实现就变得简单了。
让我们具体考虑一下使用购物车的 EC(电子商务) 服务。在 EC 服务中,经常执行以下操作。
- 显示要购买的物品
- 将您要购买的商品加入购物车
- 在收银台办理支付手续
由于在执行步骤2的动作时还没有建立购买,我们将购物车中的商品数据存入会话中,而不向后端API发送减少商品库存的请求。当您执行第 3 步中的操作时,该过程就完成了,并且向后端发出减少商品库存的请求。
通过这种方式,会话管理用于为客户端保持一个临时状态。
如果没有 BFF,可以使用客户端的存储,例如 cookie、本地存储和索引数据库。但这种情况下,无法管理大量的状态,而且需要注意安全方面的问题。
另外,如果让后端API服务器来管理会话,则需要在其他所有微服务API服务器上存储相同的状态,这会增加重复处理。使用 BFF 进行会话管理可以减少安全隐患,同时让后端 API 的实现更简单。
上传文件
文件上传是指上传图片、视频等媒体文件和TXT、CSV等文本文件的功能。上传文件时,通常会根据文件大小将其分块,并一点一点地发送,因此很难通过简单的请求/响应处理来实现,作为 API 来实现是相对困难的。让 BFF 负责这一层,可以简化 API 服务器的实现。
如果仅使用客户端和 API 服务器构建而没有 BFF,则文件上传也往往效率低下。一个特别常见的做法是在客户端用 base64 等方式对文件内容进行编码,将其转换为文本信息,然后以 JSON 的形式 POST 到服务器端。
使用base64编码时,会转换为包含padding和换行符的文本,因此容量会增加到1.4倍左右。如果是 5MB 的文件,就会变成 7MB 大小来发送,这样做是非常低效的。
为了减轻数据的传输量,可以将文件分块,作为二进制数据,一点一点地发送,或者作为FORM的multi-part发送,而不是基于文本的JSON等方法。这种的话,就无法使用简单的基于 JSON 的 API 来实现。
因此,BFF 将负责文件上传的主要接收者。它的作用是用form/multi-part代替JSON接受文件,对大文件进行分块,一点一点地接收分块数据,并将文件保存到服务端。
这样做,就只需要将文件的存储路径传递给后端 API,让 API 的实现保持简单。
像这样,在后端API服务器和客户端之间的API代理也是BFF的作用之一。文件上传是一个例子,下面的 WebSocket 也是一个类似的案例。
WebSocket、Server Sent Events、Long Polling
WebSocket、Server Sent Events 和 Long Polling 是用于客户端和服务器之间即时通信的 HTTP 扩展。特别是WebSocket是一种适合用于聊天、同步编辑等实时性强的应用的通信方式,在SNS等应用中被广泛使用。同样,Server Sent Events和长轮询(Long Polling)是在接受即时通知和执行处理时使用的一种通信方法。
这些实现方式与使用JSON格式进行简单交互的API服务器有很大不同。需要设置一个接受 WebSocket 的端点(Endpoint),在那里进行数据的实时交换,并将数据存储在数据库表中。如果由 BFF 作为这个端点,则后端 API 服务器的实现将变得更简单。
下图显示了 BFF 负责的 API 服务器和客户端之间的实时通信
作为客户端的浏览器执行“与 WebSocket 建立连接并发送消息”。发送的消息被BFF接收,BFF执行“2.将消息放入消息队列”。
消息队列执行“3.向所有的BFF实例发送消息”(当同时连接到BFF服务器的客户端数量增加时,为了保持高可用性,需要在多台服务器上创建BFF实例)。
收到队列中的消息后,向收件人发送消息,“4.另一个客户端收到消息”。在完成这些实时同步过程后,BFF 执行“5. 在后端服务器上注册消息”的过程。
与之前的File Upload类似,这里也进行了后端API的读取。
使用 BFF 时如何开始
这一篇,我们介绍了 5 个典型的案例。
- API Gateway
- 服务器端渲染(Server Side Rendering)
- 会话管理(Session Management)
- 文件上传
- WebSocket、Server Sent Events、Long Polling
除此之外,还有其他用例,例如在后端 API 中断时返回临时数据的“断路器(Circuit Breaker)”功能和“API 缓存”功能。
但是,如果什么功能都往BFF上放,负载会集中在BFF上,它可能无法履行原本的职责。 BFF 是用户界面层的服务器,由于构建微服务和富 Web 应用时的架构模式,不建议在BFF上实现过多功能。
建议从API Gateway、Server Side Rendering等典型用法入手,逐步增加功能。所以下一篇,我将介绍如何开始使用BFF。