Node做BFF中间层架构优化前端开发体验并提升系统整体性能。

news2025/7/4 2:49:04

文章目录

      • 1. BFF 层的定位
      • 2. 技术选型
      • 3. 架构设计
        • 3.1 分层设计
        • 3.2 示例架构
      • 4. 核心功能实现
        • 4.1 数据聚合
        • 4.2 权限校验
        • 4.3 缓存优化
      • 5、实战示例
      • 1. 场景说明
      • 2. ECharts 数据格式要求
      • 3. BFF 层实现步骤
        • 3.1 接收前端参数
        • 3.2 调用后端服务获取数据
      • 4. 前端使用
  • 总结


在使用 Node.js 构建 BFF(Backend for Frontend)层架构时,核心思想是为前端应用(如 Web、移动端或桌面应用)提供定制化的 API 接口,将后端复杂的服务逻辑抽象化、聚合化,从而优化前端开发体验并提升系统整体性能。

以下是基于 Node.js 构建 BFF 层架构的一些关键点和实践方法:


1. BFF 层的定位

  • 职责

    • 为前端提供专用的接口,屏蔽后端服务的复杂性。
    • 聚合多个微服务的数据,减少前端的请求次数。
    • 处理与前端相关的逻辑(如权限校验、数据格式转换、多端适配等)。
  • 位置

    • 位于前端与后端服务(如微服务、数据库等)之间,作为中间层。

2. 技术选型

  • Node.js 框架

    • Express.js:轻量级、灵活,适合快速开发。
    • Koa.js:基于 async/await 的现代框架,代码更简洁。
    • NestJS:基于 TypeScript 的企业级框架,适合大型项目。
  • 其他工具

    • GraphQL:如果需要更灵活的数据查询,可以用 Apollo Server 或 GraphQL.js。
    • 微服务通信:使用 axiosnode-fetch 调用后端服务。
    • 缓存:使用 Redis 或内存缓存(如 node-cache)优化性能。
    • 监控与日志:集成 winstonpino 等日志库,以及 Prometheus 等监控工具。

3. 架构设计

3.1 分层设计
  • 路由层:处理 HTTP 请求,定义 API 接口。
  • 服务层:封装业务逻辑,调用后端服务或数据库。
  • 数据聚合层:从多个数据源获取数据并整合成前端需要的格式。
  • 适配器层:处理与前端相关的逻辑(如格式转换、权限校验等)。
3.2 示例架构
plaintext
	Frontend (Web/Mobile)

	         ↓

	BFF Layer (Node.js)

	   ├── Router (定义 API 接口)

	   ├── Service (业务逻辑)

	   ├── Aggregator (数据聚合)

	   ├── Adapter (前端适配)

	   └── External Services (调用后端微服务/数据库)

4. 核心功能实现

4.1 数据聚合
  • 假设有一个电商应用,前端需要展示商品详情,包括商品信息、库存、用户评价等。

  • BFF 层可以调用多个微服务:

    • 商品服务:获取商品基本信息。
    • 库存服务:获取商品库存。
    • 评价服务:获取用户评价。
  • BFF 层将这些数据整合后返回给前端。

示例代码

	const express = require('express');

	const axios = require('axios');

	const app = express();

	 

	app.get('/product/:id', async (req, res) => {

	  const productId = req.params.id;

	 

	  try {

	    // 调用多个微服务

	    const [product, inventory, reviews] = await Promise.all([

	      axios.get(`https://product-service/api/products/${productId}`),

	      axios.get(`https://inventory-service/api/inventory/${productId}`),

	      axios.get(`https://review-service/api/reviews/${productId}`),

	    ]);

	 

	    // 聚合数据

	    const result = {

	      product: product.data,

	      inventory: inventory.data,

	      reviews: reviews.data,

	    };

	 

	    res.json(result);

	  } catch (error) {

	    res.status(500).send('Error fetching product data');

	  }

	});

	 

	app.listen(3000, () => {

	  console.log('BFF server running on port 3000');

	});
4.2 权限校验
  • 在 BFF 层统一处理用户认证和权限校验。
  • 使用 JWT 或 OAuth2.0 验证用户身份。

示例代码

	const jwt = require('jsonwebtoken');

	 

	function authenticateToken(req, res, next) {

	  const authHeader = req.headers['authorization'];

	  const token = authHeader && authHeader.split(' ')[1];

	 

	  if (token == null) return res.sendStatus(401);

	 

	  jwt.verify(token, 'your-secret-key', (err, user) => {

	    if (err) return res.sendStatus(403);

	    req.user = user;

	    next();

	  });

	}

	 

	app.get('/secure-data', authenticateToken, (req, res) => {

	  res.json({ message: 'This is secure data', user: req.user });

	});
4.3 缓存优化
  • 使用 Redis 缓存热点数据,减少对后端服务的调用。

示例代码

	const redis = require('redis');

	const client = redis.createClient();

	 

	app.get('/cached-data/:id', async (req, res) => {

	  const id = req.params.id;

	  const cacheKey = `data:${id}`;

	 

	  client.get(cacheKey, async (err, data) => {

	    if (data) {

	      res.json(JSON.parse(data));

	    } else {

	      const result = await axios.get(`https://some-service/api/data/${id}`);

	      client.setex(cacheKey, 3600, JSON.stringify(result.data)); // 缓存 1 小时

	      res.json(result.data);

	    }

	  });

	});

5、实战示例

在基于 ECharts 图表的数据展示场景中,BFF(Backend for Frontend)层可以承担数据聚合和格式化的任务,从而让前端专注于图表的渲染逻辑,同时减少前端与多个后端服务的交互复杂度。


1. 场景说明

假设需要展示一个包含以下信息的 ECharts 图表:

  • 销售数据(从 sales-service 获取)。
  • 用户增长数据(从 user-service 获取)。
  • 时间范围由前端传递(如最近 7 天、30 天等)。

BFF 层的目标是:

  1. 接收前端的时间范围参数。
  2. 调用多个后端服务获取数据。
  3. 聚合数据并格式化为 ECharts 所需的格式。
  4. 返回给前端。

2. ECharts 数据格式要求

ECharts 图表通常需要以下数据结构:

  • X 轴数据:时间、分类等。
  • Y 轴数据:数值(如销售额、用户数等)。
  • 系列(series) :不同数据类型的集合。

示例 ECharts 配置

	option = {

	  xAxis: {

	    type: 'category',

	    data: ['2023-10-01', '2023-10-02', '2023-10-03'], // X 轴数据

	  },

	  yAxis: {

	    type: 'value',

	  },

	  series: [

	    {

	      name: '销售额',

	      type: 'line',

	      data: [120, 200, 150], // Y 轴数据

	    },

	    {

	      name: '用户数',

	      type: 'line',

	      data: [50, 80, 70],

	    },

	  ],

	};

3. BFF 层实现步骤

3.1 接收前端参数

前端通过查询参数传递时间范围,例如:

	GET /chart-data?startDate=2023-10-01&endDate=2023-10-07
3.2 调用后端服务获取数据

BFF 层调用多个服务获取数据,例如:

  • sales-service:返回指定时间范围内的销售数据。
  • user-service:返回指定时间范围内的用户增长数据。

示例代码

	const express = require('express');

	const axios = require('axios');

	const app = express();

	 

	app.get('/chart-data', async (req, res) => {

	  const { startDate, endDate } = req.query;

	 

	  try {

	    // 调用销售服务

	    const salesResponse = await axios.get(`https://sales-service/api/sales`, {

	      params: { startDate, endDate },

	    });

	    const salesData = salesResponse.data; // 假设返回 [{ date: '2023-10-01', amount: 120 }, ...]

	 

	    // 调用用户服务

	    const userResponse = await axios.get(`https://user-service/api/users`, {

	      params: { startDate, endDate },

	    });

	    const userData = userResponse.data; // 假设返回 [{ date: '2023-10-01', count: 50 }, ...]

	 

	    // 数据聚合与格式化

	    const dateSet = new Set();

	    const salesMap = {};

	    const userMap = {};

	 

	    // 收集所有日期

	    salesData.forEach(item => dateSet.add(item.date));

	    userData.forEach(item => dateSet.add(item.date));

	 

	    // 构建日期数组

	    const xAxisData = Array.from(dateSet).sort();

	 

	    // 填充销售数据

	    salesData.forEach(item => {

	      salesMap[item.date] = item.amount;

	    });

	 

	    // 填充用户数据

	    userData.forEach(item => {

	      userMap[item.date] = item.count;

	    });

	 

	    // 构建 Y 轴数据

	    const salesSeries = xAxisData.map(date => salesMap[date] || 0);

	    const userSeries = xAxisData.map(date => userMap[date] || 0);

	 

	    // 返回 ECharts 所需格式

	    res.json({

	      xAxis: xAxisData,

	      series: [

	        { name: '销售额', type: 'line', data: salesSeries },

	        { name: '用户数', type: 'line', data: userSeries },

	      ],

	    });

	  } catch (error) {

	    res.status(500).send('Error fetching chart data');

	  }

	});

	 

	app.listen(3000, () => {

	  console.log('BFF server running on port 3000');

	});

4. 前端使用

前端只需要调用 BFF 层提供的接口,并直接将返回的数据传递给 ECharts:

	fetch('/chart-data?startDate=2023-10-01&endDate=2023-10-07')

	  .then(response => response.json())

	  .then(data => {

	    const option = {

	      xAxis: {

	        type: 'category',

	        data: data.xAxis,

	      },

	      yAxis: {

	        type: 'value',

	      },

	      series: data.series,

	    };

	    const chart = echarts.init(document.getElementById('main'));

	    chart.setOption(option);

	  });

总结

通过以上方法,你可以使用 Node.js 构建一个高效、灵活的 BFF 层架构,为前端提供更好的开发体验,同时优化后端服务的调用效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2337767.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于autoware1.14的实车部署激光雷达循迹,从建图、定位、录制轨迹巡航点、到实车运行。

1.首先安装autoware ,大家可以以下一下博客进行安装,如果缺少库什么的直接问ai安装对应的库就行。ubuntu18.04安装Autoware1.14---GPU版 最全环境配置说明_autoware1.14安装教程-CSDN博客 安装成功后运行: source install/setup.bash roslau…

云计算(Cloud Computing)概述——从AWS开始

李升伟 编译 无需正式介绍亚马逊网络服务(Amazon Web Services,简称AWS)。作为行业领先的云服务提供商,AWS为全球开发者提供了超过170项随时可用的服务。 例如,Adobe能够独立于IT团队开发和更新软件。通过AWS的服务&…

UE学习记录part18

225 animation blueprint templates: generic animation blueprints 在Animation Blueprint中选择template生成动画蓝图模板 在function中选择blurprintthreadsafeupdateanimation,用于做数据的更新 先创建变量,再将变量再blueprintinitializeanimation…

刀片服务器的散热构造方式

刀片服务器的散热构造是其高密度、高性能设计的核心挑战之一。其散热系统需在有限空间内高效处理多个刀片模块产生的集中热量,同时兼顾能耗、噪音和可靠性。以下从模块化架构、核心散热技术、典型方案对比、厂商差异及未来趋势等方面展开分析: 一、模块化散热架构 刀片服务器…

【每日八股】复习计算机网络 Day1:TCP 的头部结构 + TCP 确保可靠传输 + TCP 的三次握手

文章目录 复习计算机网络 Day1TCP 的头部结构TCP 如何保证可靠传输?1. 数据完整性保障2. 顺序与去重控制3. 流量与拥塞控制4. 连接控制5. 其他辅助机制TCP 可靠传输的保障手段总结 TCP 的三次握手?TCP 为什么要三次握手?TCP 三次握手出现报文…

device_fingerprint、device_id、hmac生成

文章目录 1. 写在前面2. 设备信息3. 数美指纹 【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python…

python抓取HTML页面数据+可视化数据分析(投资者数量趋势)

本文所展示的代码是一个完整的数据采集、处理与可视化工具,主要用于从指定网站下载Excel文件,解析其中的数据,并生成投资者数量的趋势图表。以下是代码的主要功能模块及其作用: 1.网页数据获取 使用fetch_html_page函数从目标网…

uboot下读取ubifs分区的方法

在uboot 的defconfig中增加以下内容: CONFIG_MTDIDS_DEFAULT"nand0nand0" CONFIG_MTDPARTS_DEFAULT"mtdpartsnand0:1M(boot1),1M(boot2),1M(hwinfo),6M(kernel1),6M(kernel2),56M(rootfs1),56M(rootfs2),-(ubi2)" CONFIG_CMD_UBIy 其中&#x…

HAL详解

一、直通式HAL 这里使用一个案例来介绍直通式HAL,选择MTK的NFC HIDL 1.0为例,因为比较简单,代码量也比较小,其源码路径:vendor/hardware/interfaces/nfc/1.0/ 1、NFC HAL的定义 1)NFC HAL数据类型 通常定…

MCP(模型上下文协议)说明

背景 MCP(Model Context Protocol,模型上下文协议)旨在解决大型语言模型(LLM)与外部数据源及工具集成的问题。由Anthropic公司于2024年11月提出并开源,目标是实现AI模型与现有系统的无缝集成。 解决的问题…

orcad csi 17.4 DRC规则设置及检查

rCAD绘制完原理图之后总是需要开启DRC检测,但是DRC一般都是英文版的,下面基于Cadence17.4 的orCAD16.6 对DRC的界面做简单的介绍 首先,鼠标点击原理图,然后再点击右上方的小勾图标 desine rules check option选项的界面 电气规…

前端资源加载失败后重试加载(CSS,JS等引用资源)

前端资源加载失败后的重试 .前端引用资源时出现了资源加载失败(这里针对的是路径引用异常或者url解析错误时) 解决这个问题首先要明确一下几个步骤 1.什么情况或者什么时候重试 2.如何重试 3.重试过程中的边界处理 这里引入里三个测试脚本,分别加载里三个不同的脚…

【HDFS入门】联邦机制(Federation)与扩展性:HDFS NameNode水平扩展深度解析

目录 引言 1 NameNode水平扩展原理 1.1 传统HDFS架构的局限性 1.2 联邦机制的基本原理 1.3 联邦架构的关键组件 2 多个Namespace的路由规则配置 2.1 客户端挂载表概念 2.2 挂载表配置示例 2.3 挂载表匹配规则 2.4 配置示例 3 BlockPool与Namespace的映射关系 3.1 B…

AI推荐系统的详细解析 +推荐系统中滤泡效应(Filter Bubble)的详细解析+ 基于Java构建电商推荐系统的分步实现方案,结合机器学习与工程实践

以下是AI推荐系统的详细解析: 一、核心概念 定义 推荐系统是通过分析用户行为、物品特征或用户画像,向用户推荐个性化内容的技术,广泛应用于电商、视频、社交等领域。 目标 提升用户留存与转化率增强用户体验实现精准营销 二、技术原理 1…

CSS 美化页面(五)

一、position属性 属性值‌‌描述‌‌应用场景‌static默认定位方式,元素遵循文档流正常排列,top/right/bottom/left 属性无效‌。普通文档流布局,默认布局,无需特殊定位。relative相对定位,相对于元素原本位置进行偏…

无约束最优化问题的求解算法--梯度下降法(Gradient Descent)

文章目录 梯度下降法梯度下降法原理(通俗版)梯度下降法公式学习率的设置**如何选择学习率?** 全局最优解梯度下降法流程损失函数的导函数三种梯度下降法**梯度下降法核心步骤回顾****优缺点详解****1. 全量梯度下降 (Batch Gradient Descent,…

Python全功能PDF工具箱GUI:支持转换、加密、旋转、图片提取、日志记录等多功能操作

使用Python打造一款集成 PDF转换、编辑、加密、解密、图片提取、日志追踪 等多个功能于一体的桌面工具应用(Tkinter ttkbootstrap PyPDF2 等库)。 ✨项目背景与开发动机 在日常办公或学习中,我们经常会遇到各种关于PDF文件的操作需求&#…

计算机视觉---相机标定

相机标定在机器人系统中的作用 1.确定相机的内部参数 相机的内部参数包括焦距、主点坐标、像素尺寸等。这些参数决定了相机成像的几何关系。通过标定,可以精确获取这些参数,从而将图像中的像素坐标与实际的物理坐标建立联系。例如,已知相机…

【AI插件开发】Notepad++ AI插件开发实践:支持配置界面

一、引用 此前的系列文章已基本完成了Notepad的AI插件的功能开发,但是此前使用的配置为JSON配置文件,不支持界面配置。 本章在此基础上集成支持配置界面,这样不需要手工修改配置文件,直接在界面上操作,方便快捷。 注…

数据库原理及应用mysql版陈业斌实验四

🏝️专栏:Mysql_猫咪-9527的博客-CSDN博客 🌅主页:猫咪-9527-CSDN博客 “欲穷千里目,更上一层楼。会当凌绝顶,一览众山小。” 目录 实验四索引与视图 1.实验数据如下 student 表(学生表&…