3. Node-RED核心概念
在开始构建物联网仪表盘之前,必须透彻理解 Node-RED 的五大核心概念。它们是整个编程模型的基石,决定了你如何组织逻辑、传递数据以及管理状态。本章将逐一拆解这些概念,并通过对比表格和结构图帮助你建立清晰的认知。
3.1 核心概念总览
Node-RED 是一种流式编程工具。你可以把它想象成一个电子电路:节点是元器件,连线是导线,流是电路板,消息是电流,而上下文则是电路中的储能元件或寄存器。下表快速对比了这五个概念的角色:
| 概念 | 英文 | 类比 | 核心作用 |
|---|---|---|---|
| 流 | Flow | 电路板 / 工作区标签 | 组织与隔离逻辑单元,一个标签页就是一个流 |
| 节点 | Node | 元器件 / 功能块 | 执行具体操作:输入、处理、输出 |
| 连线 | Wire | 导线 / 信号线 | 连接节点,定义数据流动方向 |
| 消息 | Msg | 电流 / 数据包 | 节点间传递数据的标准载体 |
| 上下文 | Context | 寄存器 / 全局变量 | 跨节点、跨流、跨部署存储状态 |
学习提示: 初学时最容易混淆的是 Msg 和 Context。记住一条原则:Msg 是流动的,随消息传递而销毁;Context 是驻留的,在服务器内存中持续存在。
3.2 流 (Flow) —— 逻辑容器
流是 Node-RED 编辑器顶部的一个标签页。每个标签页代表一个独立的流,拥有自己的画布空间。流的核心价值在于逻辑分组:你可以将温度采集逻辑放在“传感器流”,将仪表盘显示逻辑放在“仪表盘流”,两者通过上下文或消息桥接。
- 默认流: 新建项目时自动创建名为“Flow 1”的标签页。
- 命名规范: 双击标签页可重命名,建议使用有业务含义的名称,如
设备数据采集、告警处理。 - 跨流通信: 流之间不能直接连线,必须通过 Context 或 Link 节点 实现数据交换。
3.3 节点 (Node) —— 功能单元
节点是 Node-RED 中最基本的执行单元。每个节点都遵循 输入 → 处理 → 输出 的模型。根据功能,节点可分为三大类:
| 类别 | 典型节点 | 功能描述 |
|---|---|---|
| 输入节点 | inject, mqtt in, http in |
接收外部数据或触发事件,产生消息 |
| 处理节点 | function, change, switch |
转换、过滤、路由消息内容 |
| 输出节点 | debug, mqtt out, http response |
将消息发送到外部系统或调试面板 |
关键属性: 每个节点都有 属性面板(双击节点打开)。属性面板中配置的参数决定了节点的行为。例如,
mqtt in 节点需要配置 Broker 地址和 Topic。
3.4 连线 (Wire) —— 数据通路
连线是节点之间的有向连接,用鼠标从一个节点的输出端口拖拽到另一个节点的输入端口即可创建。连线决定了消息的传递路径。
- 单输出 → 多输入: 一个输出端口可以连接多个输入端口,消息会广播到所有下游节点。
- 多输出 → 单输入: 多个输出端口可以连接到同一个输入端口,消息会合并进入该节点。
- 删除连线: 选中连线后按
Delete键,或右键选择“删除”。 - 连线颜色: 默认灰色;当消息通过时,连线会短暂变为绿色,表示有数据流动。
3.5 消息 (Msg) 对象 —— 数据载体
消息对象是 Node-RED 中唯一的数据交换格式。它是一个标准的 JavaScript 对象,在节点之间流动。最核心的属性是 msg.payload,它承载了实际的数据内容。
一个典型的消息对象结构如下:
{
"_msgid": "a1b2c3d4", // 自动生成的唯一消息ID
"topic": "sensor/temp", // 主题,常用于 MQTT 或路由
"payload": { // 核心数据负载
"temperature": 25.6,
"humidity": 68.2,
"unit": "celsius"
},
"req": null, // HTTP 请求对象(仅 HTTP 节点使用)
"res": null // HTTP 响应对象(仅 HTTP 节点使用)
}
| 属性 | 类型 | 说明 |
|---|---|---|
msg._msgid |
String | 消息唯一标识,用于调试追踪 |
msg.topic |
String | 可选,用于消息分类或路由 |
msg.payload |
任意类型 | 核心数据,可以是字符串、数字、对象、数组、Buffer |
msg.req / msg.res |
Object | 仅 HTTP 相关节点使用,包含请求/响应信息 |
常见错误: 在
function 节点中直接修改 msg 的引用(如 msg = {payload: 123})会导致下游节点收不到消息。正确做法是修改现有属性:msg.payload = 123。
3.6 上下文 (Context) —— 状态存储
上下文提供了跨节点、跨流、跨部署的数据持久化能力。它分为三个作用域:
| 作用域 | 访问方式 | 生命周期 | 典型用途 |
|---|---|---|---|
| 节点级 | context.set('key', value) |
节点实例存活期间 | 存储节点内部计数器、临时缓存 |
| 流级 | flow.set('key', value) |
流标签页存活期间 | 同一流内多个节点共享数据 |
| 全局级 | global.set('key', value) |
Node-RED 进程运行期间 | 跨流共享设备状态、全局配置 |
在 function 节点中读写上下文的示例:
// 读取全局上下文中的设备列表
var devices = global.get('deviceList') || [];
// 添加新设备
devices.push({ id: 'sensor-01', value: msg.payload });
// 写回流级上下文
flow.set('latestDevice', devices[devices.length - 1]);
// 返回消息
return msg;
3.7 核心概念关系图
下图展示了五个核心概念在 Node-RED 运行时中的协作关系:
3.8 消息在连线中的流动过程
为了让你更直观地理解消息如何穿越节点和连线,下图展示了一个典型的“温度采集→处理→显示”流程:
3.9 最佳实践与避坑指南
✅ 推荐做法:
- 在
function节点中始终使用msg.payload作为主要数据字段,保持与社区一致。 - 使用
flow上下文存储流内共享状态,避免滥用global导致命名冲突。 - 为每个流标签页命名,并添加注释节点说明流的功能。
❌ 常见错误:
- 在
function节点中直接返回null或undefined,导致下游节点收不到消息。应返回msg或[msg, null]。 - 混淆
msg.payload和msg本身,在change节点中错误地设置整个msg对象。 - 在上下文中存储大型对象(如整个数据库结果),导致内存泄漏。
调试技巧: 在关键节点后添加
debug 节点,并在调试面板中查看 msg 的完整结构。这是理解消息流动最直接的方法。