You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Node.js Multer按文件类型设置文件大小限制方法咨询

按文件类型设置Multer差异化大小限制的实现方案

嘿,这个需求我之前刚搞定过!Multer默认的limits.fileSize是全局统一的,但我们可以通过自定义文件过滤器+监听文件流的方式,轻松实现按文件类型差异化设置大小限制,甚至还能提前中止超大文件的上传,避免浪费服务器带宽和存储资源。

实现思路

  1. 先定义好不同文件类型的规则(正则匹配+对应大小限制),方便后续维护
  2. 在自定义fileFilter里,先判断文件所属类型,拿到对应的大小限制
  3. 监听文件上传流,实时计算已上传的字节数,一旦超过对应类型的限制,立即中止上传并返回明确错误
  4. 同时设置全局最大限制(取所有类型中最大的那个值),作为第一道防线

完整代码示例

首先,我们先定义各个文件类型的规则:

// 定义不同类型文件的大小限制(单位:字节)
const fileSizeRules = {
  image: {
    // 匹配扩展名或MIME类型
    match: /jpeg|jpg|png|gif/i,
    maxSize: 4 * 1024 * 1024 // 4MB
  },
  video: {
    match: /mp4|avi/i,
    maxSize: 10 * 1024 * 1024 // 10MB
  },
  audio: {
    match: /mp3|flac|wav|m4a/i,
    maxSize: 1 * 1024 * 1024 // 1MB
  }
};

接下来配置Multer的存储和自定义文件过滤器:

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

// 配置磁盘存储
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    // 替换成你的实际上传目录
    cb(null, path.join(__dirname, 'uploads'));
  },
  filename: (req, file, cb) => {
    // 生成唯一文件名,避免重复
    const uniqueName = `${Date.now()}-${file.originalname}`;
    cb(null, uniqueName);
  }
});

// 自定义文件过滤器,实现差异化大小限制
const customFileFilter = (req, file, cb) => {
  // 1. 判断文件所属类型
  let targetRule = null;
  // 从扩展名和MIME类型两个维度匹配,提升准确性
  const fileExt = file.originalname.split('.').pop().toLowerCase();
  const mimeType = file.mimetype.toLowerCase();

  Object.values(fileSizeRules).forEach(rule => {
    if (rule.match.test(fileExt) || rule.match.test(mimeType)) {
      targetRule = rule;
    }
  });

  if (!targetRule) {
    return cb(new Error('不支持该文件类型,请上传图片、视频或音频文件'), false);
  }

  // 2. 监听文件流,实时检查大小
  let uploadedBytes = 0;
  const maxAllowedBytes = targetRule.maxSize;

  file.stream.on('data', (chunk) => {
    uploadedBytes += chunk.length;
    // 如果已上传大小超过限制,立即中止上传
    if (uploadedBytes > maxAllowedBytes) {
      file.stream.destroy(); // 终止文件流
      const maxSizeMB = maxAllowedBytes / (1024 * 1024);
      cb(new Error(`文件大小超过限制:该类型文件最大允许${maxSizeMB}MB`), false);
    }
  });

  // 3. 符合条件,允许上传
  cb(null, true);
};

// 初始化Multer实例,设置全局最大限制(取所有类型中的最大值)
const upload = multer({
  storage: storage,
  fileFilter: customFileFilter,
  limits: {
    fileSize: 10 * 1024 * 1024 // 全局最大10MB,和视频的限制一致
  }
});

最后在路由中使用,并添加错误处理:

const express = require('express');
const app = express();

// 单文件上传接口
app.post('/upload', upload.single('file'), (req, res) => {
  res.status(200).json({
    message: '文件上传成功',
    fileInfo: {
      name: req.file.filename,
      size: req.file.size,
      type: req.file.mimetype
    }
  });
});

// 全局错误处理中间件,捕获Multer相关错误
app.use((err, req, res, next) => {
  // 处理Multer自带的错误(比如全局大小限制触发)
  if (err instanceof multer.MulterError) {
    if (err.code === 'LIMIT_FILE_SIZE') {
      return res.status(400).json({ error: '文件大小超过全局最大限制(10MB)' });
    }
    return res.status(400).json({ error: err.message });
  }
  // 处理我们自定义的错误
  if (err.message) {
    return res.status(400).json({ error: err.message });
  }
  // 其他未知错误
  next(err);
});

app.listen(3000, () => {
  console.log('服务器运行在http://localhost:3000');
});

注意事项

  • 双重类型校验:同时检查文件扩展名和MIME类型,避免恶意文件绕过校验
  • 权限设置:确保上传目录uploads有正确的读写权限,否则会导致上传失败
  • 错误提示:返回明确的错误信息,方便前端用户理解问题所在
  • 资源清理:如果上传中途被中止,Multer不会自动删除已上传的部分文件,你可以在错误处理中添加逻辑清理这些临时文件(可选)

内容的提问来源于stack exchange,提问作者Lukas Morinyo

火山引擎 最新活动