Multer 实战:Node.js 文件上传完全指南

Multer 是 Express 生态标准的文件上传中间件。本文讲解磁盘/内存存储配置、多文件与多字段上传、文件类型与大小校验及错误处理。

最佳实践
事件循环与异步任务流转插画

Multer 通过 multer({ storage }) 配置存储引擎,路由中用 upload.single('avatar')、upload.array('photos', 5)、upload.fields() 接收文件,fileFilter 与 limits 把关安全。文件信息在 req.file/req.files,校验失败的错误走 Express 错误处理链。

Multer 的核心概念

基于 Busboy 构建,处理 multipart/form-data 编码的表单。三个核心配置:storage(存哪)、fileFilter(收不收)、limits(多大)。上传的文件先过过滤器、再写存储,全程流式处理。

基础配置

npm install multer
const multer = require('multer');
const path = require('path');

const storage = multer.diskStorage({
  destination: './uploads/',
  filename: (req, file, cb) => {
    // 防重名 + 保留扩展名
    const unique = Date.now() + '-' + Math.round(Math.random() * 1e9);
    cb(null, unique + path.extname(file.originalname));
  },
});

const upload = multer({
  storage,
  limits: { fileSize: 5 * 1024 * 1024 },  // 5MB 上限
  fileFilter: (req, file, cb) => {
    const allowed = ['.jpg', '.jpeg', '.png', '.webp'];
    const ext = path.extname(file.originalname).toLowerCase();
    if (allowed.includes(ext)) cb(null, true);
    else cb(new Error('仅支持图片文件'));
  },
});

app.post('/avatar', upload.single('avatar'), (req, res) => {
  res.json({ filename: req.file.filename, size: req.file.size });
});

多文件与多字段

// 同名字段多文件(最多 5 个)
app.post('/photos', upload.array('photos', 5), (req, res) => {
  res.json({ count: req.files.length });
});

// 不同字段各收文件
app.post('/profile', upload.fields([
  { name: 'avatar', maxCount: 1 },
  { name: 'gallery', maxCount: 8 },
]), (req, res) => {
  res.json({
    avatar: req.files.avatar[0].filename,
    gallery: req.files.gallery.map(f => f.filename),
  });
});

错误处理

Multer 的错误分两类:MulterError(超限等,code 如 LIMIT_FILE_SIZE)与自定义错误(fileFilter 拒绝)。统一在错误中间件处理:

app.use((err, req, res, next) => {
  if (err instanceof multer.MulterError) {
    const messages = { LIMIT_FILE_SIZE: '文件超过大小限制', LIMIT_FILE_COUNT: '文件数量超限' };
    return res.status(400).json({ error: messages[err.code] || '上传失败' });
  }
  if (err) return res.status(400).json({ error: err.message });
  next();
});

安全清单

  • 扩展名白名单不够——生产环境校验真实 MIME(file-type 库读文件头);
  • 文件名永不信任用户输入:自行生成存储名(如上例),防路径穿越;
  • 内存存储慎用:multer.memoryStorage() 适合小文件直传对象存储的场景,大文件会把内存打爆;
  • 上传目录设非执行权限,图片直接直出其余类型强制下载。

跟踪上传失败发生的阶段

Multer 实战需要把请求校验、文件接收、内容检查和对象存储写入区分开。向观测云上报脱敏的失败阶段、文件大小区间和耗时,结合已插桩的存储调用排查超时。不要把原始文件内容、上传令牌或个人文件名写入日志;监控用于定位故障,不代替文件类型验证、鉴权与恶意内容检测。

接入文档:日志采集 · Node.js APM 接入 · 监控器与告警策略。

常见问题(FAQ)

Q:上传进度怎么实现?

Multer 层无进度 API。前端用 XMLHttpRequest 的 upload.onprogress 事件(axios 的 onUploadProgress)——进度统计在客户端完成。

Q:大文件/分片上传怎么做?

Multer 不适合 GB 级文件。方案:前端分片 + 合并接口,或 tus 协议(tus-node-server),或云厂商的直传方案(OSS/S3 预签名 URL)。

Q:Fastify 项目能用 Multer 吗?

Fastify 有自己的 @fastify/multipart(基于 Busboy,流式 API 更现代)。Fastify 项目优先用官方插件。


参考文档

本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台