You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

n8n自定义节点如何实现类似S3的主节点含多操作节点结构?

解决n8n自定义节点合并为单一主节点带多操作的问题

问题根源

你之前在package.json中把两个独立的节点文件(authenticate.node.js、uploadFile.node.js)都配置到main数组里,n8n会将它们识别为两个独立核心节点,这就导致搜索时出现两个节点,同时每个节点内又保留了操作下拉框的冗余结构。

正确实现步骤

1. 修正package.json节点配置

只保留一个主节点文件的路径,让n8n识别为单一核心节点:

"nodes": {
  "main": [
    "dist/nodes/main/company.node.js"
  ]
}

2. 整合节点代码到单一文件(company.node.ts)

你现有的Company类已经定义了操作选项和对应的参数显示规则,只需要补充execute方法,根据选中的操作执行对应逻辑即可。完整代码示例:

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

export class Company implements INodeType {
  description: INodeTypeDescription = {
    displayName: 'Company',
    name: 'company',
    icon: 'file:Company.png',
    group: ['transform'],
    version: 1,
    description: 'Create a project and translate a file in this node.',
    defaults: {
      name: 'Company',
      color: '#4B8BBE',
    },
    inputs: ['main'],
    outputs: ['main'],
    properties: [
      {
        displayName: 'Operation',
        name: 'operation',
        type: 'options',
        options: [
          {
            displayName: 'Authenticate',
            name: 'authenticate',
            value: 'authenticate',
            description: 'Authenticate your account',
          },
          {
            displayName: 'Upload File',
            name: 'uploadFile',
            value: 'uploadFile',
            description: 'Upload a file in Company',
          },
        ],
        default: 'authenticate',
        description: 'Select the operation',
      },
      {
        displayName: 'Username',
        name: 'username',
        type: 'string',
        default: '',
        displayOptions: {
          show: {
            operation: ['authenticate'],
          },
        },
        description: 'The username for authentication',
        required: true,
      },
      {
        displayName: 'Password',
        name: 'password',
        type: 'string',
        typeOptions: {
          password: true,
        },
        displayOptions: {
          show: {
            operation: ['authenticate'],
          },
        },
        default: '',
        description: 'The password for authentication',
        required: true,
      },
      {
        displayName: 'Project Name',
        name: 'projectName',
        type: 'string',
        displayOptions: {
          show: {
            operation: ['uploadFile'],
          },
        },
        default: '',
        description: 'Name of the project to create.',
      },
      {
        displayName: 'Source Language',
        name: 'sourceLanguage',
        type: 'string',
        displayOptions: {
          show: {
            operation: ['uploadFile'],
          },
        },
        default: '',
        description: 'Source language of the project.',
      },
      {
        displayName: 'Target Language',
        name: 'targetLanguage',
        type: 'string',
        displayOptions: {
          show: {
            operation: ['uploadFile'],
          },
        },
        default: '',
        description: 'Target language of the project.',
      },
      {
        displayName: 'File Input',
        name: 'fileInput',
        type: 'string',
        displayOptions: {
          show: {
            operation: ['uploadFile'],
          },
        },
        default: '',
        placeholder: 'Select file...',
        typeOptions: {
          multipleValues: false,
          multipleValueButtonText: 'Add File',
        },
        required: true,
        description: 'The file to be processed.',
      },
    ],
  };

  async execute(this: IExecuteFunctions): Promise<void> {
    const items = this.getInputData();
    const operation = this.getNodeParameter('operation', 0) as string;

    for (let i = 0; i < items.length; i++) {
      try {
        if (operation === 'authenticate') {
          // 执行认证逻辑
          const username = this.getNodeParameter('username', i) as string;
          const password = this.getNodeParameter('password', i) as string;
          // 替换为实际认证API调用逻辑
          const authResult = { success: true, message: 'Authentication successful' };
          this.appendOutputData([{ json: authResult }]);
        } else if (operation === 'uploadFile') {
          // 执行文件上传逻辑
          const projectName = this.getNodeParameter('projectName', i) as string;
          const sourceLang = this.getNodeParameter('sourceLanguage', i) as string;
          const targetLang = this.getNodeParameter('targetLanguage', i) as string;
          const fileInput = this.getNodeParameter('fileInput', i) as string;
          // 替换为实际文件上传API调用逻辑
          const uploadResult = { 
            success: true, 
            project: projectName, 
            sourceLanguage: sourceLang, 
            targetLanguage: targetLang,
            file: fileInput
          };
          this.appendOutputData([{ json: uploadResult }]);
        }
      } catch (error) {
        if (this.continueOnFail()) {
          this.appendOutputData([{ json: { error: error.message }, pairedItem: { item: i } }]);
          continue;
        }
        throw error;
      }
    }
  }
}

3. 关键说明

  • 操作与参数联动:通过displayOptions.show.operation配置,让不同操作只显示对应参数,和S3节点逻辑一致。
  • 单一节点文件:所有操作逻辑都放在同一个Company类中,n8n会将其识别为一个主节点,搜索时仅显示"Company",选中后通过顶部下拉框切换操作。
  • 分支执行逻辑:在execute方法中根据选中的operation参数,执行对应业务逻辑,确保不同操作功能正常运行。

内容的提问来源于stack exchange,提问作者Tomás Da Mota

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 10:45:04