n8n自定义节点开发:从基础到高级功能的实战进阶

2026-04-06 12 0

别只用现成节点了,你的业务逻辑才是核心竞争力

在 N8N 大学的后台私信里,笔者最常听到的一句话是:“这个需求 n8n 原生节点好像做不到。”

比如,你想把客户发来的复杂 PDF 里的特定条款提取出来,再根据条款算个违约金;又或者,你想调用一个不支持 Webhook 的老旧 ERP 系统数据。这时候,纯拖拽的自动化流程就像被蒙住了眼睛,有力使不出。

这就是为什么我们需要**自定义节点(Custom Nodes)**。它不是什么高不可攀的黑科技,而是让你的 n8n 实现“完全体”的关键钥匙。今天,笔者就带你从零开始,手把手写一个能用的自定义节点,并进阶到处理复杂逻辑。

准备工作:磨刀不误砍柴工

在开始写代码之前,我们需要搭建一个开发环境。别慌,不需要你是全栈大神,只需几个基础工具:

  1. Node.js 环境:建议安装最新的 LTS 版本(v18 或 v20+),这是运行 JavaScript 的基础。
  2. 代码编辑器:VS Code 是首选,插件丰富,调试方便。
  3. n8n 实例:本地安装的 n8n 开发环境最佳(使用 npm run dev 启动),方便热更新调试。如果你是用 Docker,建议在本地映射一个开发目录。

自定义节点本质上就是一个符合 n8n 接口规范的 TypeScript/JavaScript 类。我们不需要从零搭建项目结构,n8n 官方提供了一个非常棒的脚手架工具。

核心实操:开发你的第一个“计算器”节点

我们不搞虚的,直接做一个实用的功能:**“两数相加并格式化输出”**。虽然逻辑简单,但它涵盖了自定义节点的所有核心概念:输入、处理、输出。

第一步:初始化项目结构

打开终端,运行以下命令初始化项目:

npx create-n8n-node

脚手架会询问你一些基本信息,比如节点名称(例如 n8n-nodes-custom-math)和描述。全部回车默认即可。完成后,你会得到一个标准的项目文件夹。

进入目录,安装依赖:

cd n8n-nodes-custom-math
npm install

第二步:编写节点逻辑代码

nodes 文件夹下,找到 CustomMath.ts(或类似名称)的文件。这是我们的主战场。我们需要修改 execute 方法,这里是数据处理的逻辑所在。

我们需要接收 Input Item,获取两个参数(num1 和 num2),相加后,写入一个新的字段 output。

import {
    IExecuteFunctions,
    INodeExecutionData,
    INodeType,
    INodeTypeDescription,
} from 'n8n-workflow';

export class CustomMath implements INodeType {
    description: INodeTypeDescription = {
        displayName: 'Custom Math',
        name: 'customMath',
        icon: 'file:math.svg',
        group: ['transform'],
        version: 1,
        description: '简单的加法计算器',
        defaults: {
            name: 'Custom Math',
            color: '#1A82e2',
        },
        inputs: ['main'],
        outputs: ['main'],
        properties: [
            // 这里定义 UI 上的参数输入框
            {
                displayName: 'Number 1',
                name: 'num1',
                type: 'number',
                default: 0,
                required: true,
            },
            {
                displayName: 'Number 2',
                name: 'num2',
                type: 'number',
                default: 0,
                required: true,
            },
        ],
    };

    async execute(this: IExecuteFunctions) {
        const items = this.getInputData();
        let item: INodeExecutionData;

        // 遍历每一行数据
        for (let i = 0; i < items.length; i++) {
            try {
                // 获取用户在界面上填写的参数
                const num1 = this.getNodeParameter('num1', i) as number;
                const num2 = this.getNodeParameter('num2', i) as number;

                // 核心逻辑:加法运算
                const result = num1 + num2;

                // 构造输出数据
                // 复制原有数据,并在 json 字段中添加 result
                item = {
                    json: {
                        ...items[i].json,
                        result: result,
                    },
                };

                // 将结果推送到输出流
                if (!this.shouldContinueExecution(items[i])) {
                    return [items.slice(0, i)];
                }
                items[i] = item;
            } catch (error) {
                // 简单的错误处理
                if (this.continueOnFail()) {
                    items[i] = { json: { error: error.message } };
                    continue;
                }
                throw error;
            }
        }
        return this.prepareOutputData(items);
    }
}

第三步:编译与注册

代码写好了,我们需要把它编译成 n8n 能识别的格式。在项目根目录运行:

npm run build

编译成功后,你会在 dist 目录下看到生成的文件。接下来,我们需要让 n8n 加载这个节点。

如果你是本地开发环境,可以直接把整个项目文件夹复制到 n8n 的自定义节点目录(通常是 ~/.n8n/custom)。如果是 Docker 环境,你需要在 docker-compose.yml 中映射卷:

volumes:
  - ./custom-nodes:/home/node/.n8n/custom

重启 n8n 服务后,打开编辑器界面,在节点搜索框输入 "Custom Math",你会发现我们的新节点已经躺在那里了。拖拽出来,填入两个数字,运行,见证奇迹的时刻。

进阶实战:处理复杂数据与错误

刚才的加法只是入门。在实际工作中,我们需要处理更复杂的场景,比如 API 调用、文件读取或批量数据处理。这里有两个进阶技巧。

1. 异步处理与 API 调用

很多自定义节点需要调用外部 API。这时候必须使用 async/await

假设我们要调用一个天气 API。在 execute 方法中,我们需要使用 await this.helpers.httpRequest(...)。这是 n8n 提供的内置 HTTP 客户端,它自动处理了认证、Header 等细节。

const response = await this.helpers.httpRequest({
    method: 'GET',
    url: `https://api.example.com/weather?city=${city}`,
    headers: {
        'Authorization': `Bearer ${token}`
    }
});
item.json.weather = response;

记住,n8n 的节点是单线程逻辑,但在高并发下,正确处理 Promise 链能避免内存泄漏。

2. 完善的错误处理(避坑指南)

很多新手开发的节点一报错就直接卡死整个工作流。这是一个巨大的坑。请务必使用 try...catch 包裹你的核心逻辑,并利用 n8n 的 continueOnFail 机制。

在上面的加法代码中,我已经展示了基础写法。在进阶版中,你应该在 catch 块里返回更详细的错误信息,而不是简单的 error.message

避坑细节: 当你使用 continueOnFail 时,输出的数据结构必须保持一致。如果你在正常情况下输出 { json: { result: 1 } },那么在错误情况下,你也应该输出 { json: { error: "..." } }。否则,下游节点可能会因为字段缺失而报错。

如何发布与分享你的节点

当你开发完一个通用的节点(比如对接了某个特定 API),不要只在本地吃灰。N8N 大学鼓励大家开源分享。

  1. 发布到 NPM:运行 npm publish。这样全世界的 n8n 用户都可以通过 npm install <你的包名> 来使用。
  2. 供内部使用:将编译后的 dist 文件夹打包,分发给团队成员,让他们放入自定义节点目录即可。

发布到 NPM 是标准做法,但如果你的节点包含敏感逻辑(如硬编码的密钥),请务必使用环境变量(process.env.MY_KEY)来管理。

FAQ:常见问题解答

在 N8N 大学的社区里,关于自定义节点开发的常见疑问如下:

Q1: 我不会 TypeScript,能用 JavaScript 开发吗?

可以。虽然官方推荐 TypeScript(类型检查更安全),但 n8n 底层运行在 Node.js 环境。你可以直接写 JavaScript 代码,只需要确保导出的类符合 n8n 的接口规范即可。不过,为了减少运行时错误,笔者强烈建议至少学一点 TS 的基础。

Q2: 自定义节点能访问本地文件系统吗?

能。因为 n8n 运行在 Node.js 环境中,你可以使用 fs 模块直接读写服务器上的文件。但请注意,如果你使用的是 Docker 部署,需要正确配置卷映射(Volume Mapping),否则文件写入后在容器重启时会丢失。

Q3: 为什么我的节点在界面上显示不出来?

通常有三个原因:
1. 编译失败:检查 npm run build 是否有报错。
2. 路径错误:确保编译后的文件位于 ~/.n8n/custom 或 Docker 映射的目录中。
3. 缓存问题:尝试重启 n8n 服务(pm2 restart n8n 或重启 Docker 容器)。

总结与资源

自定义节点开发是 n8n 进阶的必经之路。它让你摆脱了平台的限制,能够将任何复杂的业务逻辑封装成一个可复用的黑盒。从简单的数学计算,到对接私有 API,再到处理二进制文件,自定义节点的能力边界就是你想象力的边界。

不要害怕写代码。从今天开始,尝试把你工作流中重复出现的逻辑抽离出来,写成一个自定义节点。这不仅能提升效率,更是你掌握自动化核心能力的体现。

参考资源:

相关文章

n8n API集成踩坑记:认证失败与请求超时的实战解决方案
n8n API连接超时?排查网络、防火墙与超时设置的实战记录
n8n API集成收费吗?一文讲清社区版与企业版的边界
n8n免费版API集成与认证:如何突破节点限制实现自动化?
n8n API集成时,我踩过的那些认证坑
n8n API密钥配置指南:手把手教你搞定认证

发布评论