BFF架构WEB项目的持续交付部署优化与实践-上

 

本文介绍了我主导负责的公司内部研发管理平台(使用人数约为210人)前端项目的持续交付部署优化与实践,该项目采用了BFF架构,有 Node 服务作为中间层以及普遍意义上的 Web 层两个微应用,与常规的前端项目有异,交付也有所差别。

在这个过程中如何更便捷地交付运维部署升级,以及该过程不会对开发同事进行开发有所妨碍是主要的优化重心,下面的文章详细介绍了在结合公司实际业务的场景下,BFF架构项目的持续交付部署的优化与实践过程,希望对你有所帮助或启发。

项目架构介绍

项目选型背景

该项目于2021年8月启动立项,立项时参与人员有 Java 后端开发人员2名,前端开发人员4名。研发管理平台作为一个面向研发相关人员使用的应用,主要负责两个主要功能:

  1. 需要对多个渠道的数据进行处理后展示,包括运维数据,运营数据,人员代码提交量、千行代码缺陷率等;
  2. 研发人员关于研发流程的相关发布处理等业务。

由于 Java 后端开发人员只有2名,而开发工期紧,任务重,因此我主动争取了数据处理相关的业务统一交给我们前端的 Node 服务进行,而 Java 后端开发人员负责基础的账号体系、研发流程管理等相关业务。

BFF架构

BFF,意思是 Backend For Frontend (服务于前端的后端),服务端设计 API 是为前端的使用而考虑,主要是为解决以下几个痛点:

  • 常规的服务端字段类型不符合前端业务要求,需要进行再处理;
  • 让多个接口合并为一个,接口聚合。

采用BFF架构增加一个中间层,让前端可以聚焦业务模型,也解放了后端,让其专心提供基础服务,不用再为各种前端而定制返回数据字段类型。

BFF架构只是一种逻辑分层概念,不是一种专门的技术,因此你可以使用任何语言来实现,比如 Python 、 Java 、 Go 、 Node 等。而对于我的团队状况来说前端开发人员多,因此我这边采用的是 Node 服务来充当 BFF 层。

BFF架构分层选型

BFF 层

BFF 层为研发管理平台 Web 层提供数据预处理、接口聚合等功能,我们选用了 Nest.js 框架来实现 Node 服务, Nest.js 框架使用了 TypeScript , 良好的 OOP(面向对象编程)设计,业界使用人员也广泛,研发过程中相关问题基本都能在网上找到解决思路与方法.

Web 层

基于 Create React App 脚手架 搭建的 Web 应用。

项目文件结构

项目文件夹下面最外层是基于 Nest.js 框架的 node 服务代码, 下属 fronted 文件夹是基于 Create React App 脚手架 的 Web 应用。

BFF代码结构

常规交付部署方式

虽然 Node 服务提供基本的静态内容服务,可以让客户访问静态 html 。但是在生产实践中,应该使用 nginx 作为 web 的服务器,以便减轻在Node.js进程上所面临的负载问题,让 Node 服务更专心地提供 API 服务。

因此在生产部署时最基本的就是分别部署 Node 服务 与 Web 服务。

常规交付部署 Web

使用 npm run build 生成生产版本的 build 目录,该目录下包含 public 下的资源文件以及压缩后的JavaScript 和 CSS 文件。然后交付 build 文件目录给运维使用 nginx 代理提供客户访问.

常规交付部署 Nest.js

在生产环境中通常并不会直接执行 node /dist/main.js 命令来运行 Node 服务,通常会使用 守护进程管理工具 pm2 来启动 Node 服务。因为其提供了自动重载、性能监控、负载均衡、日志记录等功能。

实际 Nest.js 应用交付部署过程如下

Nestjs交付部署流程

需要注意的是若服务器上没有 Node 环境以及 pm2 ,需要运维人员先安装再进行部署 Nest.js 应用。

使用 nginx 反向代理统一 BFF 层与 Web 层端口

上面两步分别部署的 Nest.js 应用以及 Web 应用是使用的不同本地端口,如假设 Nest.js 应用使用的是5000端口, Web 应用使用的是3000端口,那么会导致用户在使用的时候有割裂感,也会导致 Web 应用访问 Nest.js 应用的 API 会出现跨域问题。这时候我们需要让运维同事配置 nginx 反向代理,统一 BFF 层与 Web 层的端口。

  1. 修改 Nest.js 应用的 main.ts 文件,配置统一 API 前缀;
    async function bootstrap() {
      const app = await NestFactory.create(AppModule, {
     bufferLogs: true,
      });
      // 给所有接口添加前缀 api
      app.setGlobalPrefix('api');
      await app.listen(process.env.PORT || 5000);
    }
    
  2. 配置 nginx 反向代理 http://xxx.com/api/*http://xxx.com:5000/api/*
    server {
     listen 80;
     # 这里修改为Web应用供用户访问域名
     server_name xxx.com www.xxx.com;
     # 这里修改为服务器的 Web 应用目录
     root	/var/www/xxx.com/web/;
     index index.html;
    
     location /api/ {
         proxy_pass http://127.0.0.1:5000;
     }
    
     location / {
         try_files $uri $uri/ /index.html;
     }
    }
    
  3. 修改 Web 应用的访问 Nest.js 应用的 BaseUrl 为 http://xxx.com/,此时已统一 BFF 层与 Web 层的端口,并成功解决跨域问题。

架构全景图如下:

BFF架构全景

总结

本文总结了 BFF 架构下的前端项目的常规交付部署方法以及如何使用 nginx 解决 bff 层与 web 层端口不一致导致的跨域问题,篇幅所限,进一步的优化交付方法在下一篇文章给出,希望对大家有所启发,谢谢。

参考文档

Pattern: Backends For Frontends – Sam Newman