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

文章目录

      • 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 示例架构
plaintextFrontend (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.mzph.cn/news/901874.shtml

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

相关文章

文件系统 软硬连接

🌻个人主页:路飞雪吖~ 🌠专栏:Linux 目录 一、理解文件系统 🌠磁盘结构 二、软硬连接 🌟软硬链接 🌠软链接: 🌠硬链接: 🌟理解软硬链接的应…

单片机 | 基于51单片机的自动循迹小车设计

以下是一个基于51单片机的自动循迹小车设计详解,包含原理、公式和完整代码: 一、系统原理 核心模块: 传感器:红外对管(TCRT5000)x4主控芯片:STC89C52RC(51单片机)电机驱动:L298N驱动模块电源:7.4V锂电池(电机) + 5V稳压(单片机)工作原理: 红外对管发射红外线,…

2025.04.17【Stacked area】| 生信数据可视化:堆叠区域图深度解析

文章目录 生信数据可视化:堆叠区域图深度解析堆叠面积图简介为什么使用堆叠面积图如何使用R语言创建堆叠面积图安装和加载ggplot2包创建堆叠面积图的基本步骤示例代码 解读堆叠面积图堆叠面积图的局限性实际应用案例示例:基因表达量随时间变化 结论 生信…

基于单片机的智能养生油炸炉系统设计与实现

标题:基于单片机的智能养生油炸炉系统设计与实现 内容:1.摘要 本文针对传统油炸炉功能单一、无法满足现代养生需求的问题,设计并实现了基于单片机的智能养生油炸炉系统。通过采用STC89C52单片机作为控制核心,结合温度传感器、液位传感器、继电器等硬件&…

QML与C++:基于ListView调用外部模型进行增删改查(附自定义组件)

目录 引言相关阅读项目结构文件组织 核心技术实现1. 数据模型设计联系人项目类 (datamodel.h)数据模型类 (datamodel.h)数据模型实现 (datamodel.cpp) 2. 主程序入口点 (main.cpp)3. 主界面设计 (Main.qml)4. 联系人对话框 (ContactDialog.qml)5. 自定义组件CustomTextField.qm…

【MySQL】事务ACID理解记忆

事务的 ACID 特性详解 数据库中的 事务(Transaction) 是一组操作的集合,这些操作要么全部执行,要么全部不执行。为了保证事务可靠执行,必须满足 ACID 四大特性: 特性英文缩写简要说明原子性Atomicity事务…

MYSQL “Too Many Connections“ 错误解决

1.查询当前连接数 show status like "Threads_connected"; 2.查询数据库最大连接数 show variables like "max_connections" 3.查询所有活动连接 show processlist; 4.根据查询结果观察是否有长时间未被释放的连接 参数解释 : 字段说明id连接的唯一…

Python爬虫实战:基于 Scrapy 框架的微博数据爬取研究

一、引言 1.1 研究背景 在当今数字化时代,社交媒体已成为信息传播和公众交流的重要平台。微博作为国内极具影响力的社交媒体之一,每日产生海量的用户生成内容,涵盖新闻资讯、社交互动、娱乐八卦、热点话题讨论等多个领域。这些数据不仅反映了公众的兴趣偏好、情感态度和社…

猫咪如厕检测与分类识别系统系列【九】视频检测区域在线绘制+支持摄像头+网络摄像头+整体构建【上】

前情提要 家里养了三只猫咪,其中一只布偶猫经常出入厕所。但因为平时忙于学业,没法时刻关注牠的行为。我知道猫咪的如厕频率和时长与健康状况密切相关,频繁如厕可能是泌尿问题,停留过久也可能是便秘或不适。为了更科学地了解牠的如…

【AI插件开发】Notepad++ AI插件开发实践:支持多平台多模型

引言 上篇文章我们的Notepad插件介绍到Dock窗口集成,本篇将继续完善插件功能,主要包括两个部分: 支持多平台、多模型支持多种授权验证、接口类型 一、多平台 原先的配置项很简单: // PluginConf.h class PlatformConf { publ…

【C#】Socket通信的使用

在C#中,Socket通信是一种用于实现网络通信的底层技术。通过Socket,程序可以在网络上与其他设备进行数据交换。以下是如何使用C#中的System.Net.Sockets命名空间来实现Socket通信的详细步骤。 1. Socket通信的基本概念 Socket: 一个Socket是网络通信的端…

2024年第九届团队程序设计天梯赛c++题解L1-L3-1(附PTA网址)

L1-1 编程解决一切 5分 L1-097 编程解决一切 - 团体程序设计天梯赛-练习集 (pintia.cn)https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?problemSetProblemId1781658570803388416 #include<bits/stdc.h> #define int long long using namesp…

ICMAN防水触摸芯片 - 复杂环境下精准交互,提升触控体验

▍核心优势 ◆ 超强抗干扰能力 ◆ 工业级设计&#xff0c;一致性和稳定性好 ▍提供场景化解决方案 【智能厨电矩阵】抽油烟机档位调节 | 电磁炉火力触控 | 洗碗机模式切换 【卫浴设备方案】淋浴房雾化玻璃控制 | 智能马桶触控面板 | 浴缸水位感应 【工业控制应用】仪器仪…

Golang|抽奖相关

文章目录 抽奖核心算法生成抽奖大转盘抽奖接口实现 抽奖核心算法 我们可以根据 单商品库存量/总商品库存量 得到每个商品被抽中的概率&#xff0c;可以想象这样一条 0-1 的数轴&#xff0c;数轴上的每一段相当于一种商品&#xff0c;概率之和为1。 抽奖时&#xff0c;我们会生…

OpenCV 图形API(43)颜色空间转换-----将 BGR 图像转换为 LUV 色彩空间函数BGR2LUV()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从BGR色彩空间转换为LUV色彩空间。 该函数将输入图像从BGR色彩空间转换为LUV。B、G和R通道值的传统范围是0到255。 输出图像必须是8位无符…

【Python】用Python写一个俄罗斯方块玩玩

【Python】用Python写一个俄罗斯方块玩玩 一、引言1.成品效果展示 二、思考准备1.思考设计2.代码设计2.1 游戏页面2.2 控件设计2.2.1 方块生成2.2.2 方块碰撞2.2.3 方块消融2.2.4 游戏主循环2.2.5 游戏窗口 三、游戏完整版 一、引言 今日看到侄子在玩游戏&#xff0c;凑近一看…

维港首秀!沃飞长空AE200亮相香港特别行政区

4月13日-16日&#xff0c;第三届香港国际创科展在香港会议展览中心盛大举办。 作为国内领先、国际一流的eVTOL主机厂&#xff0c;沃飞长空携旗下AE200批产构型登陆国际舞台&#xff0c;以前瞻性的创新技术与商业化应用潜力&#xff0c;吸引了来自全球17个国家及地区的行业领袖…

Openfein实现远程调用的方法(实操)

文章目录 环境准备一、URL中接收参数二、接收一个参数三、接收多个参数四、传递对象五、传递JSON格式数据 环境准备 下面的配置&#xff0c;服务调用方加入即可。 依赖导入&#xff1a; <!-- openfeign依赖--><dependency><groupId>org.springframe…

Bright+Data网页解锁器:旅游行业数据革命的“隐形引擎”

在数字经济浪潮中&#xff0c;旅游行业正经历前所未有的变革。当消费者指尖滑动间完成跨国酒店预订&#xff0c;当航空公司每秒调整万次舱位价格&#xff0c;背后是一场无声的数据战争。而在这场战争中&#xff0c;BrightData网页解锁器正成为旅游企业破局的关键武器——它像一…

OpenCV 图形API(38)图像滤波-----Sobel 算子操作函数Sobel()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::gapi::Sobel 函数是 OpenCV 的 G-API 模块中用于执行 Sobel 算子操作的一个函数&#xff0c;主要用于图像的边缘检测。Sobel 算子通过计算图…