第 6 期:分支与循环控制 — If、Switch 与 Loop 节点大解剖

⏱ 预计阅读 12 分钟 更新于 2026/4/9

为什么需要条件控制?

前五期我们构建的工作流都是 线性的——数据从头跑到尾,没有任何分叉。但真实业务场景永远需要"如果...就..."的决策:

  • 如果订单金额 > 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:#fff

1. 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:#fff

Switch 的三种模式

模式 说明 适用场景
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,让你的工作流拥有真正的持久化存储能力,告别外部数据库依赖。