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 项目优先用官方插件。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。