第 9 期:代码是最终兵器 — Code 节点编写 JS/Python

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

Code 节点的定位

当可视化节点无法满足你的需求(如复杂的数据结构转换、正则匹配、数学计算等),Code 节点就是你的最终兜底

graph TB
    subgraph "n8n 处理能力阶梯"
        L1[🟢 内置节点
Set / If / Merge
覆盖 70% 场景] L2[🟡 表达式
{{ $json.field }}
覆盖 20% 场景] L3[🔴 Code 节点
JS / Python
覆盖剩余 10%] end L1 --> L2 --> L3 style L3 fill:#ff6d5b,stroke:#e55a4e,color:#fff

1. 两种运行模式

🔄 Run Once for All Items(默认推荐)

一次性获取所有 Items,你自己控制遍历逻辑。

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 模式: "Run Once for All Items"
// 特点: $input.all() 返回全部 Items,你自己决定如何处理
// 适用: 聚合计算、排序、去重、分组等需要看到"全局"的场景
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

const allItems = $input.all();  // 获取全部 Items

// 示例: 按价格从高到低排序
const sorted = allItems.sort((a, b) => b.json.price - a.json.price);

// 示例: 去重 (按 email 字段)
const seen = new Set();
const unique = allItems.filter(item => {
  if (seen.has(item.json.email)) return false;  // 已见过,过滤掉
  seen.add(item.json.email);                     // 标记为已见
  return true;                                    // 保留
});

// 必须返回 Item 数组
return unique;

🔁 Run Once for Each Item

n8n 自动遍历,每个 Item 独立执行一次代码。

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 模式: "Run Once for Each Item"
// 特点: $input.item 是"当前这一个" Item
// 适用: 对每条数据做独立转换(无需看到其他 Items)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

const item = $input.item;  // 当前正在处理的 Item

// 示例: 手机号脱敏
const phone = item.json.phone;
const masked = phone.slice(0, 3) + '****' + phone.slice(-4);
// 13812345678 → 138****5678

// 返回单个 Item(不是数组!)
return {
  json: {
    ...item.json,              // 保留原有字段
    maskedPhone: masked,       // 新增脱敏字段
    processedAt: new Date().toISOString()  // 新增时间戳
  }
};

2. 内置变量与引用

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// n8n Code 节点内置变量速查表
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// 📌 当前节点数据
$input.all()                    // 所有输入 Items (Run Once for All)
$input.first()                  // 第一个 Item
$input.last()                   // 最后一个 Item
$input.item                     // 当前 Item (Run Once for Each)
$input.all().length             // Items 总数

// 📌 跨节点引用 (⭐ 极其强大!)
$('Set').all()                  // 获取 "Set" 节点的全部输出 Items
$('HTTP Request').first().json  // 获取 "HTTP Request" 节点第一条数据的 JSON
$('Telegram Trigger').first().json.message.text  // 深度跨节点引用

// 📌 工作流元信息
$execution.id                   // 当前执行 ID
$execution.mode                 // "manual" | "trigger"
$workflow.id                    // 工作流 ID
$workflow.name                  // 工作流名称

// 📌 时间函数
$now                            // 当前时间 (Luxon DateTime 对象)
$now.toISO()                    // "2026-04-09T12:00:00.000+08:00"
$now.toFormat('yyyy-MM-dd')     // "2026-04-09"
$today                          // 今天 00:00:00

// 📌 环境变量
$env.MY_SECRET_KEY              // 读取 n8n 环境变量 (安全!)

3. 实战案例集

案例 1: CSV 文本解析

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 场景: 将一段 CSV 文本拆解为结构化 Items
// 输入: { "json": { "csvData": "姓名,年龄,城市\n张三,28,上海\n李四,35,北京" } }
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

const csv = $input.first().json.csvData;
const lines = csv.split('\n');              // 按换行符分割
const headers = lines[0].split(',');        // 第一行是表头

// 跳过表头,将每行数据转为 Item
const items = lines.slice(1).map(line => {
  const values = line.split(',');
  const obj = {};
  headers.forEach((header, index) => {
    obj[header.trim()] = values[index]?.trim();  // 对齐表头与值
  });
  return { json: obj };
});

return items;
// 输出:
// [
//   { "json": { "姓名": "张三", "年龄": "28", "城市": "上海" } },
//   { "json": { "姓名": "李四", "年龄": "35", "城市": "北京" } }
// ]

案例 2: 数据分组统计

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 场景: 按城市分组,统计每个城市的订单数与总金额
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

const items = $input.all();

// 使用 reduce 做分组聚合
const grouped = items.reduce((acc, item) => {
  const city = item.json.city;
  if (!acc[city]) {
    acc[city] = { city, count: 0, totalAmount: 0 };  // 初始化分组
  }
  acc[city].count += 1;                               // 计数 +1
  acc[city].totalAmount += item.json.amount;           // 累加金额
  return acc;
}, {});

// 将分组结果转为 Item 数组输出
return Object.values(grouped).map(group => ({ json: group }));
// 输出:
// [
//   { "json": { "city": "上海", "count": 15, "totalAmount": 28500 } },
//   { "json": { "city": "北京", "count": 8,  "totalAmount": 12000 } }
// ]

案例 3: 异步操作(使用 await)

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// n8n Code 节点默认支持 async/await!
// 场景: 在 Code 节点中直接发起 HTTP 请求 (无需 HTTP Request 节点)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// ⚠️ 注意: n8n Code 节点使用 Node.js 沙箱
//    内置 fetch API 可直接使用

const response = await fetch('https://api.github.com/repos/n8n-io/n8n');
const data = await response.json();

return [{
  json: {
    repoName: data.full_name,            // "n8n-io/n8n"
    stars: data.stargazers_count,         // 50000+
    language: data.language,              // "TypeScript"
    lastUpdate: data.updated_at
  }
}];

4. Python 模式 (n8n 2.0+)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# n8n Code 节点 Python 模式
# 需要在节点设置中将 Language 切换为 "Python"
# ⚠️ 需要 N8N_RUNNERS_ENABLED=true (Task Runner)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

# 获取所有输入 Items
items = _input.all()

# 使用 Python 列表推导式进行数据处理
result = []
for item in items:
    data = item["json"]         # 访问 Item 的 json 字段
    
    # 中文姓名 → 拼音 (示例逻辑)
    processed = {
        "original": data["name"],
        "uppercased": data["name"].upper(),
        "length": len(data["name"]),
    }
    result.append({"json": processed})

return result

安全注意事项

graph TB
    subgraph "Code 节点安全模型"
        Code[💻 你的代码]
        
        Code -->|"✅ 允许"| Allow1[fetch / HTTP 请求]
        Code -->|"✅ 允许"| Allow2[JSON 处理]
        Code -->|"✅ 允许"| Allow3[数学计算]
        Code -->|"❌ 禁止"| Deny1[访问文件系统 fs]
        Code -->|"❌ 禁止"| Deny2[require 外部模块]
        Code -->|"❌ 禁止"| Deny3[子进程 child_process]
    end
    
    Note[🛡️ Task Runner 沙箱
N8N_RUNNERS_ENABLED=true] Code -.-> Note style Note fill:#22c55e,stroke:#16a34a,color:#fff

⚠️ 安全提示: 启用 N8N_RUNNERS_ENABLED=true 后,Code 节点在隔离的 Task Runner 沙箱中执行,无法访问宿主文件系统或执行系统命令,有效防止代码注入攻击。

下一步

在 Ep 10 中,我们将快速串烧 n8n 最实用的内置工具节点——Merge、Set、Edit Image、Date & Time 等,补齐日常开发的最后拼图。