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

如何实现标题与描述校验后再用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:45:03