mcpField
N
n8n-code-javascript

n8n-code-javascript

github.com/czlonkowski开发23.2k86 次安装4 天前更新
代码仓库

关于 n8n-code-javascript

为 n8n Code 节点编写 JavaScript 的指导技能,面向工作流构建者,涵盖执行模式、数据访问、返回格式及常见沙箱问题。

主要功能

  1. 01选择批量或逐项执行模式
  2. 02读取输入与 Webhook 数据
  3. 03返回有效的 n8n 数据项
  4. 04JavaScript 数据转换模式
  5. 05沙箱辅助方法与模块说明

适用场景

  1. 01汇总或筛选工作流数据项
  2. 02在 Code 节点转换数据
  3. 03排查返回格式错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/czlonkowski/n8n-mcp --skill n8n-code-javascript

安装后在 Claude Code 中输入/n8n-code-javascript确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BUILTIN_FUNCTIONS.md
COMMON_PATTERNS.md
DATA_ACCESS.md
ERROR_PATTERNS.md
README.md

详细介绍

JavaScript 代码节点

在 n8n Code 节点中编写 JavaScript 代码的专家指南。


快速入门

// Basic template for Code nodes
const items = $input.all();

// Process data
const processed = items.map(item => ({
  json: {
    ...item.json,
    processed: true,
    timestamp: new Date().toISOString()
  }
}));

return processed;
基本规则
  1. 选择“对所有项目运行一次”模式(适用于大多数用例)
  2. 访问数据:$input.all()、$input.first() 或 $input.item
  3. 返回 [{json: {...}}]——这是规范且兼容不同模式的形式。在对所有项目运行一次模式下,n8n 也会自动包装直接返回的 return {…} 对象,因此这种写法也能运行;真正会失败的是返回原始值(字符串/数字)或 null。
  4. 重要:Webhook 数据位于 $json.body 下(而不是直接位于 $json 下)
  5. 可用的内置功能:this.helpers.httpRequest()(无身份验证——在任务运行器沙盒中,裸 $helpers 全局变量为 undefined,因此调用 $helpers.httpRequest() 会抛出 ReferenceError: $helpers is not defined)、DateTime(Luxon)、$jmespath()。不可用:this.helpers.httpRequestWithAuthentication(已列入拒绝名单)、$env(当 N8N_BLOCK_ENV_ACCESS_IN_NODE=true 时)、require()(除非已列入允许名单)。对于任何超出简单免身份验证 GET 请求的需求(身份验证、分页、重试),优先使用 HTTP Request 节点,并让 Code 节点专注于纯逻辑。
  6. 实例允许名单中的库:可自托管实例可以通过 N8N_RUNNERS_ALLOWED_BUILT_IN_MODULES 和 N8N_RUNNERS_ALLOWED_EXTERNAL_MODULES 将模块列入允许名单(旧版:NODE_FUNCTION_ALLOW_BUILTIN / NODE_FUNCTION_ALLOW_EXTERNAL)。如果用户表示其实例允许使用特定模块(例如 axios、lodash、crypto),请通过 require() 使用这些模块——不要拒绝。如果不确定,请询问,或默认仅使用内置模块。
  7. 技能不匹配? 如果你正在为附加到 AI Agent 的 Custom Code Tool(@n8n/n8n-nodes-langchain.toolCode)编写代码,请停下——该节点使用不同的契约(通过 query 输入,必须返回字符串,没有 $input/$helpers)。请使用 n8n-code-tool 技能。

模式选择指南

Code 节点提供两种执行模式。请根据用例进行选择:

对所有项目运行一次(推荐 - 默认)

适用于: 95% 的用例

  • 工作方式:无论输入数量多少,代码都只执行一次
  • 数据访问:$input.all() 或 items 数组
  • 最适用于:聚合、筛选、批处理、转换,以及使用所有数据进行 API 调用
  • 性能:处理多个项目时更快(只执行一次)
// Example: Calculate total from all items
const allItems = $input.all();
const total = allItems.reduce((sum, item) => sum + (item.json.amount || 0), 0);

return [{
  json: {
    total,
    count: allItems.length,
    average: total / allItems.length
  }
}];

适用场景:

  • ✅ 跨数据集比较项目
  • ✅ 计算总和、平均值或统计数据
  • ✅ 对项目排序或排名
  • ✅ 去重
  • ✅ 生成汇总报告
  • ✅ 合并多个项目中的数据
对每个项目运行一次

适用于: 仅限特殊情况

  • 工作方式:针对每个输入项目分别执行代码
  • 数据访问:$input.item 或 $item
  • 最适用于:针对单个项目的逻辑、独立操作、逐项验证
  • 性能:处理大型数据集时较慢(需多次执行)
// Example: Add processing timestamp to each item
const item = $input.item;

return [{
  json: {
    ...item.json,
    processed: true,
    processedAt: new Date().toISOString()
  }
}];

适用场景:

  • ✅ 每个项目都需要独立的 API 调用
  • ✅ 针对每个项目进行验证,并采用不同的错误处理方式
  • ✅ 根据项目属性进行针对性转换
  • ✅ 业务逻辑要求分别处理各个项目

快速决策:

  • 需要查看多个项目? → 使用“所有项目”模式
  • 每个项目都完全独立? → 使用“每个项目”模式
  • 不确定? → 使用“所有项目”模式(你随时可以在内部循环)
为什么“All Items”更快——逐项边界

在 Code 节点中,模式选择是影响性能的最大因素。每个逐项执行上下文都会产生设置开销(在 n8n 2.x 上针对小型记录测得):

每项运行的内容大致开销
Code All Items(对整个数据集运行一次)~0.02 ms/项
任意节点中的表达式(IF / Set / 等)~0.2 ms/项
Code Each Item(每项一个完整沙箱)~0.6 ms/项 — 比 All Items 慢约 25–30 倍

对 10k 个项使用 Run Once for Each Item,纯开销约为 ~6 s,而 Run Once for All Items 约为 ~0.2 s。只有在确实需要隔离单个项时才使用 Each Item(例如独立的错误处理,或无法批处理的逐项 API 调用);否则,应在一个 All Items 节点内部循环。表达式本身的复杂度几乎没有开销(约 90% 的成本来自逐项上下文,而不是代码),且每次节点之间的跳转都会重新复制所有项——因此要减少逐项边界的数量,而不是对每个边界做微优化。项数少于几百时,这些都无关紧要;只有在热路径上(项数多、I/O 少)才需要关注。

参见:DATA_ACCESS.md → “Mode Performance”,了解推论、跳转开销和规模检查。


数据访问模式

从上游节点获取数据的四种方式。请注意,$node["Name"] 和 $('Name') 需要使用 .first().json 或 .all()——不能直接使用 .json。

const allItems = $input.all();          // 1. All items — batch ops, aggregation (most common)
const data = $input.first().json;       // 2. First item — single objects, API responses
const item = $input.item;               // 3. Current item — "Each Item" mode ONLY (undefined otherwise)
const other = $node["Webhook"].json;    // 4. Named node — combine data across nodes

始终通过 .json 访问字段(例如 item.json.name,而不是 item.name),并优先使用明确的 $input.first().json.field,而不是直接使用 $json.field。

参见:DATA_ACCESS.md,查看完整指南——包含每种模式的示例、决策树和常见错误(修改原始数据、缺少长度检查、在错误的模式中使用 $input.item)。


关键:Webhook 数据结构

最常见的错误:Webhook 数据嵌套在 .body 下

// ❌ WRONG - Will return undefined
const name = $json.name;
const email = $json.email;

// ✅ CORRECT - Webhook data is under .body
const name = $json.body.name;
const email = $json.body.email;

// Or with $input
const webhookData = $input.first().json.body;
const name = webhookData.name;

原因:Webhook 节点会将所有请求数据封装在 body 属性下。这包括 POST 数据、查询参数和 JSON 负载。

参见:DATA_ACCESS.md,了解完整的 Webhook 结构详情


返回格式要求

规范形式:[{json: {...}}]——一个数组,其中的每个对象都有一个 json 属性。它明确无歧义,且在两种执行模式下的行为完全相同,因此应将其作为默认格式。

在 Run Once for All Items 模式下,n8n 会在输出时自动规范化较宽松的结构:单个裸对象或裸对象数组都会自动封装在 json 下。因此 return {foo: 1} 可以运行。无法封装、因此会在运行时真正失败并报错 "Code doesn't return items properly" 的是原始值(字符串/数字/布尔值)或 null/undefined。(n8n-mcp ≥ 2.63.0 不再将裸对象返回标记为错误,因为这反映了自动封装行为。)

正确的返回格式
// ✅ Single result
return [{
  json: {
    field1: value1,
    field2: value2
  }
}];

// ✅ Multiple results
return [
  {json: {id: 1, data: 'first'}},
  {json: {id: 2, data: 'second'}}
];

// ✅ Transformed array
const transformed = $input.all()
  .filter(item => item.json.valid)
  .map(item => ({
    json: {
      id: item.json.id,
      processed: true
    }
  }));
return transformed;

// ✅ Empty result (when no data to return)
return [];

// ✅ Conditional return
if (shouldProcess) {
  return [{json: processedData}];
} else {
  return [];
}
非规范返回值(会自动封装——建议使用规范形式)
// ⚠️ Auto-wrapped in All Items mode → [{json: {field: value}}]. Runs, but prefer the array form.
return {
  json: {field: value}
};

// ⚠️ Auto-wrapped → [{json: {field: value}}]. Runs, but add the json wrapper for clarity.
return [{field: value}];

// ✅ Fine — input items already carry a json property, so returning them unchanged is a valid passthrough
return $input.all();
确实有问题的返回值
// ❌ FAILS: primitive — n8n errors "Code doesn't return items properly"
return "processed";

// ❌ FAILS: null / undefined — nothing to pass to the next node
return null;

重要性:规范形式 [{json: {...}}] 明确无歧义,且在两种模式下的行为相同。n8n 会在 All Items 模式下自动规范化裸对象和对象数组,但原始值或 null 返回值无法封装,会导致执行停止。

参见:ERROR_PATTERNS.md #3,查看详细的错误解决方案


常见模式概览

来自生产工作流中最实用的 Code 节点结构。先看一个快速示例——对所有项求和/聚合:

const items = $input.all();
const total = items.reduce((sum, item) => sum + (item.json.amount || 0), 0);
return [{ json: { total, count: items.length, average: total / items.length } }];

完整的模式库包含 10 种模式:多源聚合、正则表达式筛选、Markdown/结构化文本解析、JSON 比较、CRM/表单转换、版本发布处理、带计算字段的数组转换、Slack Block Kit 格式化、前 N 项排名,以及字符串聚合报告——每种模式都包含不同变体。

参见:COMMON_PATTERNS.md,查看 10 种详细的生产模式(以及最佳实践章节:验证输入、try-catch、尽早筛选、优先使用数组方法而非循环、使用 console.log 调试)。


错误预防——常见错误

Code 节点反复出现的故障,按大致发生频率排序:

  1. 代码为空/缺少返回值——始终以 return [...] 结束,并确保每个分支都有返回值。
  2. 把表达式语法当作代码——JavaScript 代码中不要写 {{ }}(return {{ $json.x }} 会导致语法错误)。请使用 `${$json.field}` 或 $input.first().json.field。在字符串字面量内部使用 {{ }} 没问题——它只是 n8n 不会求值的字面文本。
  3. 返回值形状——优先使用 return [{json:{...}}]。在 All Items 模式下,裸写 return {…} 会自动包装,但返回基本类型(字符串/数字)或 null 才会真正导致失败。
  4. 缺少 null 检查——使用可选链:item.json?.user?.email || 'fallback'。
  5. Webhook 请求体嵌套——$json.email 未定义;请使用 $json.body.email。
  6. 身份验证辅助函数被禁用(httpRequestWithAuthentication),且 $env 被禁用——请通过凭据/HTTP Request 节点处理密钥,而不是在 Code 节点沙箱中处理。

参见:ERROR_PATTERNS.md,其中提供了完整指南——每种错误的错误/正确代码、转义规则、沙箱限制(错误 #6–#7)、预防检查清单,以及快速错误消息查找表。


内置函数与辅助工具

// HTTP requests (no auth — see sandbox note below)
const res = await this.helpers.httpRequest({ method: 'GET', url: 'https://api.example.com/data' });

// DateTime (Luxon): now, formatting, arithmetic
const now = DateTime.now();
const formatted = now.toFormat('yyyy-MM-dd');
const tomorrow = now.plus({ days: 1 });

// $jmespath() — query JSON structures
const adults = $jmespath($input.first().json, 'users[?age >= `18`]');

// $getWorkflowStaticData() — data that persists across executions

**沙箱(自 n8n v2.0 起,JsTaskRunnerSandbox):**访问器是 this.helpers.httpRequest()——这里的 $helpers 全局变量未定义($helpers.httpRequest() 会抛出 ReferenceError)。在丢失 this 的嵌套异步函数中,请使用 await fn.call(this, ...) 调用。this.helpers.httpRequestWithAuthentication 和 this.helpers.requestWithAuthenticationPaginated 被列入拒绝列表(→ UnsupportedFunctionError);进行身份验证调用时,请使用携带凭据的 HTTP Request 节点(首选)、子工作流,或仅当令牌已作为数据流经工作流时,在 this.helpers.httpRequest() 上手动设置 Authorization: Bearer ${token} 标头。当 N8N_BLOCK_ENV_ACCESS_IN_NODE=true 时,$env 会被禁用;require() 仅适用于允许列表中的模块。Buffer、URL 和标准 JS 全局对象(Math、JSON、Object、Array)始终可用。

参见:BUILTIN_FUNCTIONS.md,其中提供了完整参考——完整的 httpRequest 选项、所有 DateTime/Luxon 操作、JMESPath 模式、静态数据用例,以及沙箱限制的详细说明。


最佳实践

  • 先验证输入——处理前检查数组是否为空,以及 .json 是否缺失。
  • 对有风险的操作使用 try-catch(HTTP 调用),并返回错误对象,而不是让程序崩溃。
  • 优先使用数组方法(filter/map/reduce),而不是手动循环。
  • 尽早筛选,稍后转换——在执行开销较大的操作前缩减数据集。
  • 使用描述性名称,并通过 console.log() 调试(输出会显示在浏览器控制台中)。

参见:COMMON_PATTERNS.md → “最佳实践”,其中提供了每项实践的代码示例。


生产环境注意事项

从真实部署中总结出的宝贵经验,详见 DATA_ACCESS.md → “生产环境注意事项”:

  • SplitInBatches 的输出容易让人误解:main[0] = 完成(所有批次处理完后触发一次),main[1] = 每个批次(循环体)。在完成输出后添加一个 Limit 1 节点以确保安全。
  • 迭代次数决定成本:每次循环迭代都会通过引擎重新运行整个循环体(每次约有 0.8 ms 的开销)。batchSize: 1 相当于 Each Item 循环——应使用实际限制(速率限制、页面大小、内存)允许的最大批次大小,或者完全不循环。
  • 跨迭代累积(重要):循环结束后,$('Node Inside Loop').all() 仅返回最后一次迭代的项目。请通过 $getWorkflowStaticData('global') 进行累积(之前重置、循环内推入、之后读取)。
  • pairedItem:输出与输入不一一对应的项目时,需设置 pairedItem: { item: i },否则下游 Set 节点会因 paired_item_no_info 而失败。
  • 节点引用语法:$('Node').first().json 或 $('Node').all()——绝不要直接在引用上使用 .json。
  • 浮点精度:以分为单位比较货币金额——Math.round(a*100) !== Math.round(b*100)——避免浮点误差导致误报。

何时使用 Code 节点

使用 Code 节点之前,请先按照 n8n Expression Syntax 技能中的转换守门流程进行判断:依次尝试表达式 → Edit Fields 字段中的箭头函数 IIFE → Code 节点。前两种方式足以应对大多数“转换这些数据”任务,每次约需 1–10 ms;而 Code 节点在沙箱中运行约需 500–1000 ms——对于纯粹的单项目整形,速度相差约 100 倍,且功能并无区别。只有在需要聚合整个数据集($input.all())、使用允许列表中的库,或执行异步工作时,Code 节点才值得使用。在编写加密(HMAC、哈希、签名)或 XML/SOAP/RSS 解析代码之前,还应检查是否有原生节点——n8n 提供的 Crypto 节点(nodes-base.crypto)和 XML 节点(nodes-base.xml)无需 JavaScript 即可完成这些工作。对于原生节点已能完成的任务使用 Code 节点,是最常见的误判之一。

在以下情况使用 Code 节点:

  • ✅ 需要多个步骤的复杂转换
  • ✅ 自定义计算或业务逻辑
  • ✅ 递归操作
  • ✅ 解析结构复杂的 API 响应
  • ✅ 多步骤条件判断
  • ✅ 跨项目聚合数据

以下情况可考虑使用其他节点:

  • ❌ 简单字段映射 → 使用 Set 节点
  • ❌ 基本筛选 → 使用 Filter 节点
  • ❌ 简单条件判断 → 使用 IF 或 Switch 节点
  • ❌ 仅需发送 HTTP 请求 → 使用 HTTP Request 节点

Code 节点擅长处理:需要串联多个简单节点才能实现的复杂逻辑


与其他技能集成

配合使用:

n8n Expression Syntax:

  • 其他节点中的表达式使用 {{ }} 语法
  • Code 节点直接使用 JavaScript(无需 {{ }})
  • 了解何时使用表达式、何时使用代码

n8n MCP Tools Expert:

  • 查找 Code 节点:search_nodes({query: "code"})
  • 获取配置帮助:get_node({nodeType: "nodes-base.code"})
  • 验证代码:validate_node({nodeType: "nodes-base.code", config: {...}})

n8n Node Configuration:

  • 模式选择(All Items 与 Each Item)
  • 语言选择(JavaScript 与 Python)
  • 了解属性依赖关系

n8n Workflow Patterns:

  • 在转换步骤中使用 Code 节点
  • Webhook → Code → API 模式
  • 在工作流中处理错误

n8n Validation Expert:

  • 验证 Code 节点配置
  • 处理验证错误
  • 自动修复常见问题

快速参考清单

部署 Code 节点前,请确认:

  • 代码不为空 - 必须包含有意义的逻辑
  • 存在 return 语句 - 返回 items,而不是原始值或 null
  • 采用规范的返回格式 - 每个 item:{json: {...}}(裸对象会自动包装,但请明确指定)
  • 数据访问方式正确 - 使用 $input.all()、$input.first() 或 $input.item
  • 不要将 {{ }} 写成代码 - 使用 JavaScript 模板字面量:`${value}`
  • 错误处理 - 对 null/undefined 输入使用守卫子句
  • Webhook 数据 - 如果数据来自 webhook,通过 .body 访问
  • 模式选择 - 大多数情况下选择 “All Items”
  • 性能 - 优先使用 map/filter,而非手动循环
  • 输出一致 - 所有代码路径都返回相同结构

其他资源

相关文件
n8n 文档

准备好在 n8n Code 节点中编写 JavaScript 了! 从简单的转换开始,使用错误模式指南避免常见问题,并参考模式库中的生产就绪示例。

评论

支持 Markdown