场景导入:为什么你需要掌握 Function 节点?
在 N8N 大学的日常交流中,笔者经常听到这样的抱怨:“n8n 的节点虽然多,但总有那么些特殊的逻辑,比如复杂的字符串拼接、数据格式转换,或者调用一个生僻的 API,现有的节点配置起来太费劲了。”
这就好比你有一辆性能极佳的跑车,却只能在规定的直线上行驶。**Function 节点**,就是这辆车的“手动挡”模式。它允许你在流程中直接编写 JavaScript 代码,让你突破预设节点的限制,实现真正意义上的“随心所欲”。
掌握 Function 节点,是 n8n 从“入门”到“精通”的分水岭。它能帮你处理 JSON 数据、进行数学运算、甚至调用第三方库。接下来,笔者将带你手把手实战,彻底征服这个强大的节点。
准备工作:打开你的 n8n 沙盒
在开始编写代码之前,请确保你已经:
- 拥有一个可用的 n8n 实例(无论是云部署、Docker 还是本地安装)。
- 熟悉 n8n 的基本操作(如添加节点、连线)。
- 心理准备:不要害怕代码,n8n 的 Function 节点对 JavaScript 新手非常友好。
特别提示:n8n 使用的是 Node.js 环境,因此你可以在 Function 节点中使用 ES6+ 的语法,但请注意,由于安全限制,部分 Node.js 核心模块(如 fs 文件系统)是无法直接调用的。
核心实操:从“Hello World”到数据变形
我们将通过三个循序渐进的实战案例,带你彻底搞懂 Function 节点的运作机制。
第一步:理解输入与输出——最基本的“数据搬运”
Function 节点的核心在于处理传入的 items。你可以把它想象成一个快递中转站,包裹(数据)进来了,你重新打包(处理),然后发出去。
在 n8n 中,数据是以“批次(Batch)”的形式流动的。默认情况下,Function 节点会接收所有输入数据,处理后一次性输出。
实战代码:
// 这是一个简单的数据透传,并添加一个自定义字段
const newItem = {
json: {
...items[0].json, // 保留原数据
myCustomValue: "这是 Function 节点添加的数据", // 新增字段
timestamp: new Date().toISOString() // 添加当前时间
}
};
return [newItem];
在 n8n 中运行这段代码,你会发现输出的 JSON 中多出了 myCustomValue 和 timestamp 字段。这就是最基本的“数据注入”。
第二步:数据遍历与逻辑判断——批量处理的精髓
实战中,我们经常需要对一组数据进行过滤或转换。例如,从 API 返回的 100 条用户数据中,只筛选出“已激活”的用户。
这里我们利用 JavaScript 的 map 和 filter 方法。请注意,Function 节点必须返回一个数组,数组的每个元素就是一条输出数据。
实战代码:
// 假设输入数据是多条用户记录
// 我们只处理状态为 'active' 的用户,并将姓名转为大写
const processedItems = items
.filter(item => item.json.status === 'active') // 筛选
.map(item => ({
json: {
id: item.json.id,
name: item.json.name.toUpperCase(), // 转大写
status: item.json.status
}
}));
return processedItems;
笔者经验: 如果输入数据量很大(例如几千条),建议在 Function 节点前加一个 Split In Batches 节点,避免内存溢出导致 n8n 崩溃。
第三步:调用外部 API——在节点内发送 HTTP 请求
虽然 n8n 有专门的 HTTP Request 节点,但在某些场景下(比如需要根据输入数据动态生成 URL 参数),在 Function 节点内直接调用 API 会更灵活。
n8n 的 Function 节点支持 axios 库(通常已内置或可用)。我们可以通过 $httpRequest 方法(n8n 官方推荐方式)或直接使用 axios。
实战代码(使用 n8n 推荐的内置请求方法):
// 这是一个模拟场景:根据输入的 ID 获取详细信息
// 注意:在实际使用中,你需要确保 n8n 实例能访问目标 API
const output = [];
for (const item of items) {
// 这里为了演示,我们直接构造返回结果
// 实际开发中,你可以使用 await axios.get(...)
const response = {
id: item.json.id,
description: `ID 为 ${item.json.id} 的详细数据`,
checkedAt: new Date().toISOString()
};
output.push({ json: response });
}
return output;
这一步演示了如何在代码中构建逻辑流。你可以加入 try...catch 块来处理 API 调用失败的情况,确保流程稳定性。
避坑指南:新手最容易踩的 3 个坑
在 N8N 大学的社区里,关于 Function 节点的求助帖最多。以下是笔者总结的高频“翻车”现场:
1. 忘记返回数组或返回格式错误
错误示例:
return { json: { value: 1 } }; // 错误:这是一个对象,不是数组
正确写法:
return [{ json: { value: 1 } }]; // 正确:必须包裹在数组中
原因: n8n 的数据流是基于“批次”的,即使你只想输出一条数据,也必须将其放入数组中。
2. 混淆同步与异步代码
Function 节点默认是同步执行的。如果你在代码中使用了 async/await,n8n 也能正确处理,但你必须确保返回的是一个 Promise 或者正确使用了 await。
坑点: 很多开发者在异步回调中直接修改外部变量,导致数据丢失或返回空值。建议在异步操作中使用 Promise.all 或者使用 for...of 循环配合 await。
3. 数据类型转换陷阱
从 API 获取的 JSON 数据中,数字可能被识别为字符串(例如 "100")。如果你直接进行数学运算,可能会得到拼接字符串的结果。
避坑技巧: 在进行运算前,务必使用 parseInt()、parseFloat() 或 Number() 进行显式转换。
// 错误
return items[0].json.price + 10; // 如果 price 是 "50",结果是 "5010"
// 正确
return Number(items[0].json.price) + 10; // 结果是 60
进阶技巧:使用 n8n 的表达式与环境变量
Function 节点并不是孤岛,它可以与 n8n 的其他功能无缝结合。
1. 混合使用表达式: 你可以在 Function 节点的代码中,直接使用 n8n 的表达式语法({{ $json.field }})来获取数据,但这通常不如直接操作 items 对象直观。推荐在代码内部直接使用 items[0].json.field。
2. 访问全局变量: 如果你设置了 n8n 的全局环境变量,可以通过 process.env.YOUR_KEY 在 Function 节点中访问。
FAQ:关于 n8n Function 节点的常见问题
Q1: Function 节点的性能如何?会不会拖慢整个工作流?
对于常见的数据转换任务(几百条数据),性能几乎无感。但如果涉及复杂的循环计算或大量的外部 API 调用,性能会受限。建议将耗时操作拆分,或使用 Split In Batches 节点控制并发量。
Q2: 我可以在 Function 节点里引入第三方 npm 包吗?
标准的 n8n 版本不支持直接在界面中安装 npm 包。但如果你是通过 Docker 或 npm 自行部署,且具备服务器权限,你可以进入 n8n 的容器或目录,执行 npm install package-name 来安装依赖,然后在 Function 节点中通过 require('package-name') 引入。
Q3: 为什么我的代码在测试时能跑,正式运行时报错?
这通常是因为测试数据与真实数据结构不一致。n8n 的 Function 节点非常依赖 JSON 结构。请确保你的代码对可能出现的 undefined 值做了防御性编程(例如使用 item.json.field || 'default')。
总结与资源
Function 节点是 n8n 的灵魂所在,它赋予了自动化流程无限的扩展性。从简单的字段修改到复杂的业务逻辑编排,掌握它意味着你真正拥有了低代码开发的“超能力”。
建议初学者从修改现有数据开始,逐步过渡到编写复杂的逻辑判断。遇到报错不要慌,利用 n8n 的 Debugging 模式查看数据流转,是解决问题的最佳途径。
更多 n8n 实战教程,请持续关注 N8N大学 (n8ndx.com),笔者将持续分享更多“避坑”干货。