You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中multer文件大小验证问题:自定义中间件无法获取req.file

问题:Multer中间件前自定义文件大小验证时req.file为undefined

在Node.js应用中使用multer处理文件上传时,尝试通过自定义中间件setFileLimit根据文件类型设置动态大小限制,但该中间件执行时req.file和req.files均为undefined,无法提前验证文件大小。移除setFileLimit后,multer能正常获取文件并完成后续存储及数据库写入操作。


前端代码

// 发送媒体文件的前端逻辑
if (file) {
  const formData = new FormData()
  formData.append('medias', file)
  console.log('send rrrr--');
  console.log('type of formdata--', typeof formData);
  const mediatoCloudinary = await uploadMedia(formData)
  if (mediatoCloudinary?.status === 400) {
    console.log('media upload error', mediatoCloudinary);
    setMediaError('No media file found.')
  }
}

// 封装的上传请求函数
export const uploadMedia = async(formData) => {
  try {
    console.log('rrr--', formData);
    const result = await axiosApi.post(messagesRoute.sendMedia, formData)
    console.log('media link', result);
    return result.data
  } catch (error) {
    console.log('media error', error.message);
    return error.response
  }
}

后端路由

router.post('/sendMedia', setFileLimit, multerMid.single('medias'), catchAsyncErrors((req: Req, res: Res, next: Next) => {
  console.log('in send media route');
  messageController.saveMediaToCloudinary(req, res, next)
}))

后端Multer配置与setFileLimit中间件

// 自定义大小限制中间件
const setFileLimit = (req: Req, res: Res, next: Next) => {
  console.log('Accessing file:', req.file, 'req.files--', req.files);
  const file = req.file
  if (!file) {
    return res.status(400).send('No media file found.');
  }

  let maxSize;
  if (file.mimetype.startsWith('image/')) {
    maxSize = 5 * 1024 * 1024; // 图片最大5MB
  } else if (file.mimetype.startsWith('video/')) {
    maxSize = 10 * 1024 * 1024; // 视频最大10MB
  } else {
    maxSize = 5 * 1024 * 1024; // 其他文件默认5MB
  }

  if (file.size > maxSize) {
    return res.status(400).json({ error: 'File size exceeds the limit.' });
  }

  next()
}

// Multer磁盘存储配置
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const uploadDirectory = path.join(__dirname, '../public/media')
    if (!fs.existsSync(uploadDirectory)) {
      fs.mkdirSync(uploadDirectory, { recursive: true });
    }
    cb(null, uploadDirectory);
  },
  filename: (req, file, cb) => {
    console.log('file in multer--', file);
    const uniqueSuffix = uuidv4() + '-' + file.originalname
    cb(null, uniqueSuffix);
  },
});

// Multer实例
const multerMid = multer({
  storage: storage,
  limits: {
    fieldNameSize: 100,
    fieldSize: 5 * 1024 * 1024
  }
});

export { multerMid, setFileLimit }

解决方案

核心原因

req.file是multer中间件处理multipart/form-data请求后,才挂载到req对象上的属性。你把setFileLimit放在multer前面执行,此时multer还没解析请求中的文件数据,自然拿不到req.file。

修改方案:将验证逻辑移入multer的fileFilter

multer提供了fileFilter钩子,会在文件开始处理前触发,此时可以拿到文件的mimetype和size,刚好适合做动态大小验证,且不会存储不符合要求的文件。

修改后的multer配置如下:

const multerMid = multer({
  storage: storage,
  // 先设置一个全局最大上限(这里设为视频的最大限制10MB)
  limits: {
    fieldNameSize: 100,
    fileSize: 10 * 1024 * 1024
  },
  fileFilter: (req, file, cb) => {
    let maxSize;
    // 根据文件类型设置对应大小限制
    if (file.mimetype.startsWith('image/')) {
      maxSize = 5 * 1024 * 1024; // 图片5MB
    } else if (file.mimetype.startsWith('video/')) {
      maxSize = 10 * 1024 * 1024; // 视频10MB
    } else {
      maxSize = 5 * 1024 * 1024; // 其他文件5MB
    }

    // 验证文件大小
    if (file.size > maxSize) {
      return cb(new Error(`File size exceeds limit: ${maxSize / 1024 / 1024}MB`), false);
    }

    // 验证通过,允许存储文件
    cb(null, true);
  }
});

调整路由

移除多余的setFileLimit中间件,路由简化为:

router.post('/sendMedia', multerMid.single('medias'), catchAsyncErrors((req: Req, res: Res, next: Next) => {
  console.log('in send media route');
  messageController.saveMediaToCloudinary(req, res, next)
}))

错误处理

multer抛出的错误需要被捕获,你可以在全局错误处理中间件中处理,或者在catchAsyncErrors中捕获并返回对应响应:

// 示例全局错误处理中间件
app.use((err: Error, req: Req, res: Res, next: Next) => {
  if (err.message.includes('File size exceeds limit')) {
    return res.status(400).json({ error: err.message });
  }
  // 其他错误处理逻辑
  res.status(500).json({ error: 'Server error' });
});

内容的提问来源于stack exchange,提问作者Aswin K S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 18:03:17