第 6 期:分支与循环控制 — If、Switch 与 Loop 节点大解剖
为什么需要条件控制?
前五期我们构建的工作流都是 线性的——数据从头跑到尾,没有任何分叉。但真实业务场景永远需要"如果...就..."的决策:
- 如果订单金额 > 1000,走 VIP 审批流程
- 如果用户语言是中文,回复中文;否则回复英文
- 如果 API 返回错误,重试 3 次
graph LR
subgraph "线性流 (Ep 01-05)"
L1[触发] --> L2[处理] --> L3[输出]
end
subgraph "条件流 (本期及之后)"
C1[触发] --> C2{条件判断}
C2 -->|"满足"| C3[路径 A]
C2 -->|"不满足"| C4[路径 B]
C3 --> C5[汇合]
C4 --> C5
end
style C2 fill:#f59e0b,stroke:#d97706,color:#fff1. If 节点 — 二路分流器
If 节点是最基础的条件控制:一个条件,两个出口(True / False)。
配置结构
graph TB
Input[上游 Items] --> IF{If 节点
条件: price > 100}
IF -->|"✅ True"| TrueBranch[发送优惠券]
IF -->|"❌ False"| FalseBranch[记录日志]
style IF fill:#f59e0b,stroke:#d97706,color:#fff条件表达式语法
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// n8n If 节点支持的条件表达式类型
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 📌 数值比较
{{ $json.price > 100 }} // 大于
{{ $json.quantity <= 0 }} // 小于等于
{{ $json.score === 100 }} // 严格等于
// 📌 字符串比较
{{ $json.status === "active" }} // 完全匹配
{{ $json.email.includes("@") }} // 包含子串
{{ $json.name.startsWith("张") }} // 以...开头
{{ $json.url.endsWith(".pdf") }} // 以...结尾
// 📌 空值检测 (最常见的防御性判断)
{{ $json.data !== null }} // 非 null
{{ $json.data !== undefined }} // 非 undefined
{{ $json.items.length > 0 }} // 数组非空
// 📌 复合条件 (AND / OR)
{{ $json.age >= 18 && $json.country === "CN" }} // 且
{{ $json.role === "admin" || $json.role === "owner" }} // 或
// 📌 正则匹配
{{ /^1[3-9]\d{9}$/.test($json.phone) }} // 中国手机号格式验证
实战:订单金额分流
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 场景: 根据订单金额决定走 VIP 通道还是普通通道
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 输入 Items:
// [
// { "json": { "orderId": "A001", "amount": 2500, "customer": "张三" } }, → True
// { "json": { "orderId": "A002", "amount": 80, "customer": "李四" } }, → False
// { "json": { "orderId": "A003", "amount": 1500, "customer": "王五" } } → True
// ]
// If 条件: {{ $json.amount >= 1000 }}
// ✅ True 分支收到 2 个 Items (A001, A003)
// ❌ False 分支收到 1 个 Item (A002)
// ⚠️ 注意: 每个 Item 独立判断,不是"全部满足才走 True"!
2. Switch 节点 — 多路路由器
当你需要 3 个以上的分支时,Switch 节点是更优雅的选择。
graph TB
Input[用户请求] --> SW{Switch 节点
字段: $json.language}
SW -->|"zh"| ZH[中文处理]
SW -->|"en"| EN[英文处理]
SW -->|"ja"| JA[日文处理]
SW -->|"fallback"| DEFAULT[默认: 英文]
style SW fill:#6366f1,stroke:#4f46e5,color:#fffSwitch 的三种模式
| 模式 | 说明 | 适用场景 |
|---|---|---|
| Rules | 每个输出定义一条规则表达式 | 复杂的多条件判断 |
| Expression | 用表达式返回输出索引 (0/1/2...) | 简洁的路由逻辑 |
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Switch 节点 Rules 模式配置示例
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Output 0 (中文): {{ $json.language === "zh" }}
// Output 1 (英文): {{ $json.language === "en" }}
// Output 2 (日文): {{ $json.language === "ja" }}
// Fallback (默认): 不满足以上任何条件的 Items 走这里
// 输入:
// [
// { "json": { "user": "张三", "language": "zh" } }, → Output 0
// { "json": { "user": "Alice", "language": "en" } }, → Output 1
// { "json": { "user": "田中", "language": "ja" } }, → Output 2
// { "json": { "user": "Pierre", "language": "fr" } } → Fallback
// ]
3. Loop Over Items 节点 — 显式循环
虽然 n8n 有隐式循环(Ep 04),但某些场景需要显式控制:
- 批量 API 调用需要限速(每次只处理 10 条)
- 需要在循环中累积状态(计数器、汇总)
- 需要基于前一轮的结果决定下一轮行为
graph TB
Input[100 个 Items] --> Loop[Loop Over Items
批次大小: 10]
Loop -->|"第1批: Items 0-9"| Process[API 调用]
Process --> Loop
Loop -->|"第2批: Items 10-19"| Process
Loop -->|"..."| Process
Loop -->|"第10批: Items 90-99"| Process
Loop -->|"全部完成"| Done[汇总结果]
style Loop fill:#22c55e,stroke:#16a34a,color:#fff// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Loop Over Items 的典型用法: 批量处理 + 限速
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 配置:
// - Batch Size: 10 // 每次循环处理 10 个 Items
// - Options:
// - 在循环体内可以使用 Wait 节点暂停 1 秒
// - 防止 API 限速被触发 (Rate Limiting)
// 循环体内的 Code 节点可以通过以下方式获取当前批次信息:
const currentBatch = $input.all(); // 当前批次的 Items (最多 10 个)
const batchIndex = $('Loop Over Items').first().json.$batchIndex; // 当前批次序号
const totalBatches = $('Loop Over Items').first().json.$totalBatches; // 总批次数
console.log(`Processing batch ${batchIndex + 1} of ${totalBatches}`);
// 输出: "Processing batch 1 of 10"
4. 组合实战:智能客服分流系统
将 If、Switch、Loop 组合起来,构建一个真实的客服工单分流系统:
graph TB
Trigger[📨 Webhook
接收客服工单] --> Validate{If: 工单内容非空?}
Validate -->|"❌ 空工单"| Reject[回复: 请描述您的问题]
Validate -->|"✅ 有内容"| Classify{Switch: 工单类型}
Classify -->|"退款"| Refund[退款审批流程]
Classify -->|"技术"| Tech[技术支持队列]
Classify -->|"投诉"| Complaint[升级至主管]
Classify -->|"其他"| General[通用客服]
Refund --> Priority{If: 金额 > 500?}
Priority -->|"✅ 大额"| Manager[经理审批]
Priority -->|"❌ 小额"| Auto[自动退款]
Tech --> Loop[Loop Over Items
逐条分配技术员]
Loop --> Assign[分配给空闲技术员]
Assign --> Loop
Loop -->|"完成"| Notify[通知客户]
style Validate fill:#f59e0b,stroke:#d97706
style Classify fill:#6366f1,stroke:#4f46e5,color:#fff
style Priority fill:#f59e0b,stroke:#d97706常见陷阱
| 陷阱 | 现象 | 解决 |
|---|---|---|
| If 两个分支都没输出 | 条件表达式有语法错误 | 先在 Code 节点中测试 console.log({{ $json.field }}) |
| Switch 所有 Items 走 Fallback | 字段名大小写不匹配 | "Active" ≠ "active",使用 .toLowerCase() |
| Loop 无限循环 | 循环体内修改了 Items 数量 | 确保循环体不新增 Items 到同一批次 |
| 分支后无法汇合 | 两个分支的 Item 结构不同 | 在汇合前用 Set 节点统一字段 |
下一步
在 Ep 07 中,我们将探索 n8n 2.0 的杀手级新功能——内置 Data Tables,让你的工作流拥有真正的持久化存储能力,告别外部数据库依赖。