服务端与数据 / 进阶

Node.js 文件上传:从流式处理到对象存储确认

安全的上传链路不止一个 multer 配置。本文覆盖流式接收、魔数检测、预签名直传、对象权限和上传确认。

在读取之前就设置限制

Content-Type 和文件扩展名都由客户端提供,不能作为安全依据。服务端要限制请求体、单文件大小和文件数量,并读取文件头的魔数判断真实类型。超限后必须停止读取并清理临时对象。

网关和应用层都配置最大请求体;随机生成对象 key,不直接使用原始文件名;文件名只作为展示元数据,并移除控制字符;公开访问与私有下载使用不同 bucket 或权限策略。

用 pipeline 处理背压和错误

pipeline 会传递背压并在任一流失败时拒绝 Promise。不要把整个文件累积成 Buffer;并发上传时,这会很快耗尽堆内存。

EXAMPLE / 02File Upload
import { pipeline } from 'node:stream/promises';
import { createWriteStream } from 'node:fs';

await pipeline(
  incomingFileStream,
  createSizeLimitTransform(10 * 1024 * 1024),
  createWriteStream(tempPath, { flags: 'wx' })
);

大文件优先预签名直传

客户端向 API 申请上传,服务端校验身份、大小和类型并生成临时对象 key;服务端返回短时有效的预签名 URL 和必须携带的请求头;客户端直接上传到对象存储;客户端调用确认接口,服务端 HEAD 对象验证大小和元数据后再写业务记录。

未确认对象应放在临时前缀并设置生命周期自动清理。需要病毒扫描时,扫描完成前不要让对象公开可下载。