stream-cache

Streaming HTTP transfer cache node for self-hosted n8n.

Package Information

Released: this month
Downloads: 0 weekly / 0 monthly
Latest Version: 0.3.1

Documentation

n8n-nodes-stream-cache

用于受信任、自托管 n8n 的 HTTP/HTTPS 流式下载缓存节点。

创建一次下载任务,由 n8n 子工作流持续读取源响应;其他执行可以读取已经提交的本地缓存前缀。源服务器不需要支持 Range。正常下载不为每个读取块重新请求源文件。

0.3.1 候选包的来源和验证范围

本包是在本次会话可见的 0.3.0 源码基础上完成的本地修复候选。三个原始核心文件的 Git blob 摘要与前次交付记录一致;薄节点适配文件从可见原文复原,没有重新取得当前 GitHub 仓库字节。本轮无法确认当前远端 HEAD,也未将此版本安装进用户 n8n 实例。因此,它不是“已经从最新 main 构建并在线验收”的发行物。

配套源码/证据包保存来源清单、测试尝试和可复现差异。发布前应在完整仓库核对改动并执行其全部现有测试。本次新建的回归套件不冒充历史的 160 项完整仓库测试。

本次变化

  • Create 可以初始化缺失的末级缓存目录,创建权限 0700。
  • 直接父目录必须存在。不会递归创建祖先、猜测挂载位置或修改权限。
  • 其他操作不会创建缓存根目录。
  • 薄节点先调用 n8n 的 helpers.resolvePath() 和 helpers.isFilePathBlocked();没有这些 API、策略拒绝或返回异常时均停止,不绕过文件访问策略。
  • 根目录错误带有白名单诊断,能够区分父目录缺失、根目录缺失、非目录、只读、权限不足和策略拒绝,不暴露路径或源 URL。
  • 等待路径策略期间取消执行,策略返回后不会继续初始化缓存目录。

节点类型、六项操作、cacheDirectory 配置键及缓存数据结构没有改变;没有旧数据路由、格式代际、环境变量回退或迁移分派。

运行前提

  1. 自托管 n8n,Node.js 22 或更新;普通节点执行上下文提供上述两个文件系统 helper,以及既有 HTTP、二进制输出与执行取消 API。
  2. Linux,且 /proc/self/fd 可访问。目录初始化使用逐级 O_NOFOLLOW 和目录文件描述符,拒绝符号链接;不提供不受约束的替代路径。未验证 Windows、macOS、网络文件系统或分布式锁语义。
  3. 部署提供允许访问的持久化存储。父目录真实存在并可用于创建缓存子目录;已有缓存根不能是组或其他用户可写。推荐将专用根设为 0700。
  4. 生产者与消费者访问同一份实际存储,并且能同时取得 n8n 执行资源。多个 worker 的路径字符串相同,不代表文件系统共享。

目录分开可隔离用途,但不是操作系统安全沙箱。本节点面向受信任的工作流所有者和存储管理员,不承诺抵抗具有同等文件权限的恶意本地进程持续替换任务文件。初始化不会写入符号链接目标;失败后不会删除它无法确认独占的新根目录。

配置与首次使用

在每个 Download Cache 节点的 Cache Directory 填写固定绝对路径,例如:

/files/agent-download-cache

这个路径仅是例子,不会被当成默认目录。在这个例子中,/files 必须已经存在、由部署挂载并被 n8n 的文件访问策略允许。只有最后的 agent-download-cache 可以由 Create 创建。/files 不存在时会明确失败,不会递归建立一个看似挂载成功的空目录。

Docker 中填写的是执行容器内部路径,不是宿主机路径。程序不能创建持久卷或使跨主机存储自动共享,也不会调整 N8N_RESTRICT_FILE_ACCESS_TO 等实例设置。

cacheDirectory 仍为必填的固定字符串。表达式不求值,Request 不能覆盖目录,N8N_DOWNLOAD_CACHE_ROOT 不被读取。Create、Produce、Status、Read、Cancel、Release 对同一任务必须使用同一个根;不要在任务运行时改变位置。

**先运行 Create,再运行 Status。**查询一个尚未建立的根,得到 CACHE_ROOT_MISSING 是明确结果,不代表程序已经尝试下载或应该代替 Create 建目录。

首次初始化顺序为:

完整校验输入 → n8n路径策略 → 固定并检查现有父目录
→ 仅在末级缺失时mkdir(0700) → 重验目录与权限 → 同步目录
→ 创建任务 → 由子工作流执行源下载

路径解析器若因目标缺失返回 ENOENT,节点只再解析直接父目录一次,并对最终子目录做策略检查。不会递归寻找另一个可用祖先。

六项操作

Create 创建 queued 任务,不自行运行无人管理的后台下载。请求需明确给出预算:

{
  "url": "https://example.com/archive.tar.gz",
  "max_bytes": 536870912,
  "timeout_ms": 1800000,
  "idle_timeout_ms": 30000,
  "ttl_ms": 7200000,
  "segment_size": 1048576,
  "max_read_length": 1048576
}

这些数值是请求示例,不是官方平台上限。expected_sha256 可选;有可信摘要时填写64位小写十六进制值。

Produce 在异步子工作流中等待下载到结束、失败或取消。输入只传任务 ID:

{"download_id":"0123456789abcdef0123456789abcdef"}

Status 与 Cancel 使用相同 ID 输入。Cancel 只请求终止生产,不宣称文件完整。

Read Chunk 按偏移读取已提交范围:

{"download_id":"0123456789abcdef0123456789abcdef","offset":0,"length":1048576}

默认返回 n8n binary;文本传输可显式选择 Base64 JSON。尚未提交的范围返回 ready:false 和建议等待时间。短块本身不代表 EOF;调用方按 next_offset 继续,只有任务已完成并达到总长度才是 EOF。

Release 对完整文件要求最终接收方确认大小和整文件摘要:

{"download_id":"0123456789abcdef0123456789abcdef","receiver_size":104857600,"receiver_sha256":"完整文件的64位小写SHA-256"}

上面摘要文本只是占位说明,不是合法请求值。不能在 n8n 发出最后一块时立即删除缓存;响应丢失时应允许原位置重读。已失败/取消/过期的任务按既有条件释放。正在运行的生产者不会被 Release 强行删除。

n8n 工作流接线

继续使用现有接线,无需新的服务或调度器:

Create → Execute Sub-workflow(不等待) → 返回download_id
                           ↓
                  子工作流Produce等待完成

独立短调用 → Status / Read / Cancel / Release

Cache Directory 在所有配合的节点填写同一值。普通 Request 字段仍只含该操作的数据,不传文件路径。工作流模板不需要新的字段,但此候选源码集未重新取得远端模板,因此没有冒充重新验证现有线上接线。

错误诊断

错误码 含义
CACHE_ROOT_REQUIRED 节点目录配置缺失或不是合法绝对目录
CACHE_PARENT_MISSING 配置根的祖先/直接父级不存在;不递归创建
CACHE_ROOT_MISSING 非Create操作检查到缓存根不存在
CACHE_PATH_NOT_DIRECTORY 路径中出现普通文件而不是目录
UNSAFE_CACHE_ROOT 路径出现符号链接等不安全结构
CACHE_ROOT_NOT_PRIVATE 已有根允许组或其他用户写入
CACHE_ACCESS_DENIED 根目录操作权限不足
CACHE_READ_ONLY 根目录所在文件系统只读
CACHE_FULL 根初始化遇到容量或配额限制
CACHE_PATH_CHANGED 初始化过程中观察到路径身份改变
CACHE_PATH_BLOCKED n8n文件策略拒绝该位置
N8N_FILESYSTEM_HELPERS_REQUIRED 执行上下文缺少必要的官方文件系统API
N8N_FILESYSTEM_POLICY_ERROR helper失败或返回了不符合合同的值
CACHE_IO_ERROR 已分类的根目录初始化发生其他I/O错误

例如,安全的错误对象可带:

{"code":"CACHE_PARENT_MISSING","diagnostic":{"phase":"cache_parent","operation":"lstat","fs_code":"ENOENT"}}

正常模式抛出带该信息的错误;Continue On Fail 的 item 包含 error 和 diagnostic。只允许预定义阶段、操作和errno,不转发原始错误message/cause、源链接、请求头、缓存路径或任意诊断字段。n8n是否在界面或MCP中保留自定义字段仍需实际实例验证。

既有限制

无硬崩溃自动续传、无遗留锁自动接管。TTL 是逻辑过期,不是后台物理清理。缓存删除仍由显式释放或既有运维流程完成,不因这次修复新增自动垃圾回收。

已有根目录不会被chmod或删除;新根初始化失败也可能留下一个空目录,以免误删另一执行正在使用的根。文件正文的完整性、存储持久性和来源真实性是不同问题:源响应SHA-256与重组SHA-256一致,不等于没有可信来源摘要时也证明了业务文件真实性。

测试与安装物

配套源码包可执行:

npm ci --offline --ignore-scripts --no-audit --no-fund
npm test
npm pack --ignore-scripts

运行包只含节点实现、package.json 与本说明;测试和证据不进入npm包。独立安装后的回归通过 DOWNLOAD_CACHE_PACKAGE_ROOT 选择安装物,生产代码不读取这个测试变量。未增加第三方运行时依赖。

本地测试包括受控 HTTP、实际磁盘读写和明确标记的故障注入;n8n上下文/策略helper使用接口替身,不代表实际宿主已验收。发布/部署前应在真实实例验证允许目录、首次Create、异步生产与渐进读取,以及最终MCP接收文件。

Discussion