n8n 作为一款强大的工作流自动化工具,提供了一套丰富的内置方法和变量,让您可以直接在工作流中处理数据、访问执行信息和管理工作流状态。无论您是初学者还是想提升自动化能力,这篇教程都能帮您快速上手。
本教程将深入浅出地介绍以下核心概念:
execution 是 n8n 中一个非常重要的内置对象,它包含了当前工作流执行的所有关键信息。每当您的工作流运行时,n8n 都会自动创建一个 execution 对象,让您可以在代码节点中访问这些信息。
每个工作流执行都有一个唯一的 ID。这对于追踪、日志记录或在其他系统中引用执行非常有用。
使用场景:
示例代码:
// 在代码节点中获取执行 ID
const executionId = $execution.id;
console.log(`当前执行 ID: ${executionId}`);
// 返回包含执行 ID 的数据
return [{
json: {
executionId: executionId,
timestamp: new Date().toISOString()
}
}];当您在工作流中使用 Wait(等待)节点并设置等待 webhook 回调时,execution.resumeUrl 提供一个 webhook URL,外部系统可以调用它来恢复暂停的工作流。
使用场景:
示例代码:
// 获取恢复 URL 用于 webhook 回调
const resumeUrl = $execution.resumeUrl;
// 发送恢复 URL 到邮件或其他系统
return [{
json: {
message: '工作流已暂停,请访问下面的链接继续',
resumeUrl: resumeUrl,
expiresIn: '24 小时'
}
}];getWorkflowStaticData() 让您可以在工作流中存储和检索持久化数据。这些数据在工作流执行完成后会被保存,下次执行时仍然可以访问。这对于记录状态信息非常有用。
重要提示:
// 在代码节点中使用全局静态数据
const staticData = $workflow.getStaticData('global');
// 读取上次保存的值
const lastProcessedId = staticData.lastId || 0;
console.log(`上次处理的 ID: ${lastProcessedId}`);
// 更新静态数据(工作流执行成功后自动保存)
staticData.lastId = 100;
staticData.lastUpdated = new Date().toISOString();
return [{
json: {
message: '静态数据已更新',
lastId: staticData.lastId,
lastUpdated: staticData.lastUpdated
}
}];// 获取当前节点的静态数据
const nodeStaticData = $workflow.getStaticData('node');
// 只有这个节点能访问和修改
nodeStaticData.localCounter = (nodeStaticData.localCounter || 0) + 1;
return [{
json: {
nodeCounter: nodeStaticData.localCounter
}
}];常见使用场景:
itemMatching() 让您可以追踪数据项目在工作流中的来源。当数据经过多个节点转换后,您有时需要找到原始数据或中间步骤的数据。这个方法就是用来解决这个问题的。
理解项目链接:
每个项目都记录了它是如何生成的,从哪个上游节点来的。这形成了一条"链接",让您可以回溯项目的来源。
// 基本语法
const linkedItem = $("节点名称").itemMatching(当前项目的输入索引);
// 这会返回生成当前项目的上游节点的项目数据假设您有这样的工作流:
// 代码节点中的实现
const items = [];
for (let i = 0; i < $input.item.length; i++) {
// 获取当前简化后的项目
const simplifiedItem = $input.item(i);
// 使用 itemMatching 获取原始项目
const originalItem = $("数据源节点").itemMatching(i);
// 从原始项目中恢复邮箱
const restoredEmail = originalItem.json.email;
items.push({
json: {
name: simplifiedItem.json.name,
restoredEmail: restoredEmail,
source: '已恢复邮箱'
}
});
}
return items;.all() 方法让您可以访问节点输出的所有项目数据。这在您需要一次性处理所有数据而不是逐项处理时非常有用。
// 从当前节点获取所有项目
const allItems = $input.all();
// 从上一个节点获取所有项目
const previousNodeItems = $("上一个节点名称").all();
// 可选参数指定分支和运行索引
const itemsFromBranch = $("节点名称").all(branchIndex, runIndex);// 获取所有项目
const allItems = $input.all();
// 计算所有项目的总和
let totalAmount = 0;
allItems.forEach(item => {
totalAmount += item.json.amount;
});
return [{
json: {
totalItems: allItems.length,
totalAmount: totalAmount,
averageAmount: totalAmount / allItems.length
}
}];// 检查所有项目是否有效
const allItems = $input.all();
const validItems = [];
const invalidItems = [];
allItems.forEach((item, index) => {
if (item.json.email && item.json.email.includes('@')) {
validItems.push(item);
} else {
invalidItems.push({
index: index,
item: item,
error: '无效的邮箱格式'
});
}
});
return [{
json: {
validCount: validItems.length,
invalidCount: invalidItems.length,
validItems: validItems,
invalidItems: invalidItems
}
}];vars 提供了访问在 n8n 实例中定义的用户变量。这些变量在企业版本和部分功能中可用,用于存储跨工作流共享的配置信息。
可用性:
// 访问变量
const apiKey = vars.MY_API_KEY;
const baseUrl = vars.BASE_URL;
const timeout = vars.REQUEST_TIMEOUT;
// 在代码中使用
return [{
json: {
configuration: {
apiKey: apiKey,
baseUrl: baseUrl,
timeout: parseInt(timeout)
}
}
}];n8n 中有两种变量访问方式,了解它们的区别很重要:
| 特性 | vars | $env |
|---|---|---|
| 创建方式 | n8n UI 中创建 | 系统环境变量或 .env 文件 |
| 访问方式 | vars.VARIABLE_NAME | $env.VARIABLE_NAME |
| 作用域 | 环境特定 | 实例级别配置 |
| 修改方式 | 只读 | 不能从工作流修改 |
| 可用版本 | 企业版 | 所有版本 |
| 用途 | 工作流配置参数 | 系统级配置、密钥 |
现在让我们创建一个完整的工作流,综合运用上面学到的所有概念。这个工作流的目标是:
{
"name": "智能客户数据处理工作流",
"nodes": [
{
"parameters": {},
"id": "uuid-1",
"name": "手动触发",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [250, 300]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "1",
"name": "customerData",
"value": "=[\n {\"id\": \"C001\", \"name\": \"张三\", \"email\": \"zhangsan@example.com\", \"amount\": 1500},\n {\"id\": \"C002\", \"name\": \"李四\", \"email\": \"lisi@example.com\", \"amount\": 2500},\n {\"id\": \"C003\", \"name\": \"王五\", \"email\": \"wangwu@example.com\", \"amount\": 1800}\n]",
"type": "expression"
}
]
}
},
"id": "uuid-2",
"name": "设置客户数据",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [450, 300]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// 获取工作流静态数据\nconst staticData = $workflow.getStaticData('global');\n\n// 初始化处理计数\nif (!staticData.processedCount) {\n staticData.processedCount = 0;\n}\nif (!staticData.startTime) {\n staticData.startTime = new Date().toISOString();\n}\n\n// 获取所有客户数据\nconst allItems = $input.all();\nconst processedItems = [];\n\nlet totalAmount = 0;\nlet validCount = 0;\n\nallItems.forEach((item, index) => {\n const customer = item.json.customerData[index];\n \n // 验证数据\n const isValid = customer.email && customer.email.includes('@');\n \n if (isValid) {\n validCount++;\n totalAmount += customer.amount;\n \n processedItems.push({\n json: {\n id: customer.id,\n name: customer.name,\n email: customer.email,\n amount: customer.amount,\n status: 'valid',\n processedAt: new Date().toISOString(),\n executionId: $execution.id\n }\n });\n } else {\n processedItems.push({\n json: {\n id: customer.id,\n name: customer.name,\n email: customer.email,\n status: 'invalid',\n error: '邮箱格式不正确'\n }\n });\n }\n});\n\n// 更新静态数据\nstaticData.processedCount += validCount;\nstaticData.lastProcessTime = new Date().toISOString();\nstaticData.lastTotalAmount = totalAmount;\n\n// 返回处理结果\nreturn processedItems.map(item => ({\n json: {\n ...item.json,\n statisticsInfo: {\n totalProcessed: allItems.length,\n validCount: validCount,\n totalAmount: totalAmount,\n averageAmount: totalAmount / validCount,\n cumulativeProcessed: staticData.processedCount\n }\n }\n}));"
},
"id": "uuid-3",
"name": "处理并验证数据",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [650, 300]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// 生成最终报告\nconst allItems = $input.all();\n\nconst validItems = allItems.filter(item => item.json.status === 'valid');\nconst invalidItems = allItems.filter(item => item.json.status === 'invalid');\n\nconst totalAmount = validItems.reduce((sum, item) => sum + item.json.amount, 0);\n\nreturn [{\n json: {\n reportTitle: '客户数据处理报告',\n executionId: $execution.id,\n timestamp: new Date().toISOString(),\n summary: {\n totalCustomers: allItems.length,\n validCustomers: validItems.length,\n invalidCustomers: invalidItems.length,\n validationRate: `${((validItems.length / allItems.length) * 100).toFixed(2)}%`,\n totalAmount: totalAmount,\n averageAmount: (totalAmount / validItems.length).toFixed(2)\n },\n validCustomers: validItems.map(item => item.json),\n invalidCustomers: invalidItems.map(item => ({\n id: item.json.id,\n name: item.json.name,\n error: item.json.error\n }))\n }\n}];"
},
"id": "uuid-4",
"name": "生成报告",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [850, 300]
}
],
"connections": {
"手动触发": {\n "main": [\n [\n {\n "node": "设置客户数据",\n "type": "main",\n "index": 0\n }\n ]\n ]\n },\n "设置客户数据": {\n "main": [\n [\n {\n "node": "处理并验证数据",\n "type": "main",\n "index": 0\n }\n ]\n ]\n },\n "处理并验证数据": {\n "main": [\n [\n {\n "node": "生成报告",\n "type": "main",\n "index": 0\n }\n ]\n ]\n }\n },\n "active": false,\n "settings": {\n "executionOrder": "v1"\n }\n}节点 1 - 手动触发
节点 2 - 设置客户数据
节点 3 - 处理并验证数据
$input.all()getWorkflowStaticData() 记录处理进度$execution.id 为每条记录添加执行追踪节点 4 - 生成报告
| 方法/变量 | 语法 | 用途 | 示例 |
|---|---|---|---|
| execution.id | $execution.id | 获取执行 ID | const id = $execution.id |
| execution.resumeUrl | $execution.resumeUrl | 获取 webhook 恢复链接 | 用于 Wait 节点 |
| getStaticData() | $workflow.getStaticData('global') | 访问全局静态数据 | 记录处理进度 |
| itemMatching() | $("节点名").itemMatching(index) | 获取链接的上游项目 | 追踪数据来源 |
| .all() | $input.all() 或 $("节点名").all() | 获取所有项目 | 批量处理数据 |
| vars | vars.VARIABLE_NAME | 访问工作流变量 | const key = vars.API_KEY |
// ❌ 错误做法
// 在测试工作流时试图保存和读取静态数据
const staticData = $workflow.getStaticData('global');
staticData.counter = 1; // 在测试时不会保存!✅ 正确做法: 确保工作流是活动状态(activated),并通过触发节点或 webhook 执行,而不是在编辑器中测试。
// ❌ 错误做法 - 如果有 100 个项目,代码会执行 100 次
item.json.count = 0; // 每次都重置为 0✅ 正确做法: 使用 "mode": "runOnceForAllItems" 并用 .all() 获取所有项目:
const allItems = $input.all();
const totalCount = allItems.length;// ❌ 错误做法 - 节点名称拼写错误或不存在
const data = $("前面的节点").itemMatching(0); // 找不到!✅ 正确做法: 确保节点名称完全匹配(包括大小写):
const data = $("上一个节点的确切名称").itemMatching(0);$execution.id 用于追踪getWorkflowStaticData().all() 和一次性处理,避免逐项重复计算通过掌握这五个核心内置方法和变量,您已经拥有了构建高效 n8n 工作流的重要工具:
[1] 官方文档: https://docs.n8n.io/code/cookbook/builtin/
[2] n8n系列教程: https://www.undsky.com/blog/?category=n8n%E6%95%99%E7%A8%8B#