如何实现标题与描述校验后再用Multer完成文件上传?
解决Multer先保存文件再校验字段的问题
你的核心问题是Multer使用diskStorage时会先将文件写入磁盘,再执行后续的字段校验,导致字段缺失时文件已经被保存;同时前置校验中间件无法获取req.body,是因为form-data格式的请求需要Multer解析后才能拿到表单字段。下面提供两种可行的解决方案:
方案一:使用内存存储(Memory Storage)先校验,再写入磁盘
将文件先暂存到内存中,完成字段校验后再写入磁盘。这样校验不通过时,内存中的文件会自动释放,不会留下垃圾文件。
修改Multer配置
import multer from "multer"; import { v4 as uuidv4 } from "uuid"; import path from "path"; import fs from "fs"; import { promisify } from "util"; const writeFile = promisify(fs.writeFile); const mkdir = promisify(fs.mkdir); // 使用内存存储替代磁盘存储 const storage = multer.memoryStorage(); const fileFilter = (req, file, cb) => { const allowedFileTypes = ["image/jpeg", "image/jpg", "image/png"]; if (allowedFileTypes.includes(file.mimetype)) { cb(null, true); } else { cb(new Error("Invalid file type, only JPEG, JPG, and PNG is allowed!"), false); } }; const upload = multer({ storage, fileFilter, limits: { fileSize: 10 * 1024 * 1024 }, }); export default upload;
修改路由逻辑
app.post("/uploads", upload.single("photo"), async (req, res) => { // 先执行字段校验 const { title, description } = req.body; if (!title || !description) { return res.status(400).json({ error: "Title and description are required" }); } if (!req.file) { return res.status(400).json({ error: "File not uploaded." }); } // 确保目标目录存在 await mkdir("images", { recursive: true }); // 生成文件名并将内存中的文件写入磁盘 const filename = `${uuidv4()}-${Date.now()}${path.extname(req.file.originalname)}`; const filePath = path.join("images", filename); await writeFile(filePath, req.file.buffer); res.json({ message: "Upload successful", file: { filename, path: filePath, originalName: req.file.originalname } }); });
方案二:使用磁盘存储,校验失败时删除已上传文件
如果必须使用diskStorage,可以在字段校验失败后,手动删除已经保存的文件。
修改路由逻辑
import fs from "fs"; import { promisify } from "util"; const unlink = promisify(fs.unlink); app.post("/uploads", (req, res, next) => { upload.single("photo")(req, res, async (err) => { const { title, description } = req.body; // 字段校验失败时,删除已上传的文件 if (!title || !description) { if (req.file) { // 忽略删除失败的情况,避免二次报错 await unlink(req.file.path).catch(() => {}); } return res.status(400).json({ error: "Title and description are required" }); } if (err) { return res.status(400).json({ error: err.message }); } if (!req.file) { return res.status(400).json({ error: "File not uploaded." }); } res.send(req.file); }); });
为什么前置校验中间件无效?
因为form-data格式的请求需要Multer来解析表单字段和文件,在Multer中间件执行之前,req.body是空对象,所以无法获取title和description。必须让Multer先解析请求,再做字段校验。
内容的提问来源于stack exchange,提问作者gopinath krm
相关产品推荐
相关产品推荐

