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

如何用Multer上传多类型文件到MongoDB?排查500错误

问题描述

尝试通过Multer将视频、普通文件、PDF上传至MongoDB,使用Postman测试时出现500错误,怀疑是路由中配置多个Multer单文件上传中间件导致的,需解决该问题。

MongoDB模型代码

const mongoose = require("mongoose");
const FormCourse_schema = new mongoose.Schema({
  FormCourse: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "cards",
    required: true,
  },
  date: { type: String },
  file: { type: String },
  video: { type: String },
  pdf: { type: String },
});
module.exports = mongoose.model("FormCourse", FormCourse_schema);

上传控制器代码

exports.post_FormCourse = async (req, res, next) => {
  try {
    // if (!req.userId) return res.status(406).json({ massege: "Unauthenticated" });

    const FormCourse_id = req.body.FormCourse_id;
    const isFormCourse = FormCourse.findById(FormCourse_id);
    if (isFormCourse.lenght < 1) res.status(202).json("FormCourse not found");
    const course = new FormCourse({
      date: req.body.date,
      file: req.file.path,
      video: req.file.path,
      pdf: req.file.path,
    });
    const result = await course.save();
    res.status(200).send({
      result: result,
      request: {
        type: "GET",
        url: "localhost:3002/form/" + result._id,
      },
    });
  } catch (error) {
    res.status(404).json({ message: "invalid id", error: err });
  }
};

路由配置代码

const express = require("express");
const router = express.Router();
const FormCourses = require("../controllers/formCourses");
const checkAuth = require("../middleware/checkAuth");
const multer = require("multer");

const storageautre = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "./uploads/filesautre");
  },
  filename: function (req, file, cb) {
    cb(null, new Date().toISOString().replace(/:/g, "-") + file.originalname);
  },
});
const fileFilterautre = (req, file, cb) => {
  // reject a file
  if (file.mimetype === "application/*") {
    cb(null, true);
  } else {
    cb(null, false);
  }
};
const uploadautre = multer({
  storage: storageautre,
  fileFilter: fileFilterautre,
});

////////
const storagevideo = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "./uploads/filesvideo");
  },
  filename: function (req, file, cb) {
    cb(null, new Date().toISOString().replace(/:/g, "-") + file.originalname);
  },
});
const fileFiltervideo = (req, file, cb) => {
  // reject a file
  if (file.mimetype === "application/video") {
    cb(null, true);
  } else {
    cb(null, false);
  }
};
const uploadvideo = multer({
  storage: storagevideo,
  fileFilter: fileFiltervideo,
});
// \\\\\\
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "./uploads/files");
  },
  filename: function (req, file, cb) {
    cb(null, new Date().toISOString().replace(/:/g, "-") + file.originalname);
  },
});

const fileFilter = (req, file, cb) => {
  // reject a file
  if (file.mimetype === "application/pdf") {
    cb(null, true);
  } else {
    cb(null, false);
  }
};

const upload = multer({
  storage: storage,
  fileFilter: fileFilter,
});
/*-----------------------------get all orders-----------------------------*/
router.get("/", FormCourses.get_FormCourse);
/*-----------------------------post order -----------------------------*/
router.post(
  "/",
  uploadautre.single("file"),
  uploadvideo.single("video"),
  upload.single("pdf"),
  FormCourses.post_FormCourse
);
/*-----------------------------update order-----------------------------*/
router.patch("/:courseId", checkAuth, FormCourses.patch_FormCourse);
/*----------------------------delete order-----------------------------*/
router.delete("/:delete", checkAuth, FormCourses.delete_FormCourse);
module.exports = router;

Express App配置代码

const express = require("express");
const app = express();
const morgan = require("morgan");
// const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const cors = require("cors");
const path = require("path");

require("dotenv").config();

//-----------------------------add routers paths-----------------------------//

const cardsRouter = require("./src/router/Cards");
const formRouter = require("./src/router/FormCourses");
const histoRouter = require("./src/router/Historiques");
const secondCardsRouter = require("./src/router/SecondCards");
const usersRouter = require("./src/router/Users");
//-----------------------------Connect with mongodb-----------------------------//

mongoose
  .connect(process.env.DB_CONNECT)
  .then(() => console.log("mongo connected"))
  .catch((err) => console.log(err));

//-----------------------------middleware-----------------------------//
app.use(morgan("dev"));
app.use("/uploads", express.static("uploads"));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(cors());
app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept, Authorization"
  );
  if (req.method === "OPTIONS") {
    res.header("Access-Control-Allow-Methods", "PUT, POST, PATCH, DELETE, GET");
    return res.status(200).json({});
  }
  next();
});
// app.use(express.static(path.join(__dirname, "public")));

//-----------------------------Routers---------------------------//

app.use("/users", usersRouter);
app.use("/card", cardsRouter);
app.use("/form", formRouter);
app.use("/histoRouter", histoRouter);
app.use("/secondCardsRouter", secondCardsRouter);

//-----------------------------Handling errors---------------------//

app.use((req, res, next) => {
  const error = new Error("Not found");
  res.status(404);
  next(error);
});
app.use((error, req, res, next) => {
  res.status(500 | Error.status).json({
    message: error.message,
  });
});
module.exports = app;

问题原因

不能在同一个路由上连续使用多个single()中间件,第一个single()会解析完请求文件后丢弃剩余文件数据,后续single()找不到对应字段文件会报错,同时req.file会被覆盖,最终引发500错误。

修复方案

1. 合并Multer配置为多文件处理

使用fields()替代多个single(),可同时处理多个不同字段的文件上传:

const express = require("express");
const router = express.Router();
const FormCourses = require("../controllers/formCourses");
const checkAuth = require("../middleware/checkAuth");
const multer = require("multer");

// 统一处理不同类型文件的存储和过滤
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    // 根据字段名分配存储目录
    let dest;
    switch(file.fieldname) {
      case 'file':
        dest = "./uploads/filesautre";
        break;
      case 'video':
        dest = "./uploads/filesvideo";
        break;
      case 'pdf':
        dest = "./uploads/files";
        break;
      default:
        dest = "./uploads/others";
    }
    cb(null, dest);
  },
  filename: function (req, file, cb) {
    cb(null, new Date().toISOString().replace(/:/g, "-") + file.originalname);
  },
});

const fileFilter = (req, file, cb) => {
  // 根据字段名验证文件类型
  let isValid = false;
  switch(file.fieldname) {
    case 'file':
      isValid = file.mimetype.startsWith("application/");
      break;
    case 'video':
      isValid = file.mimetype.startsWith("video/");
      break;
    case 'pdf':
      isValid = file.mimetype === "application/pdf";
      break;
  }
  if (isValid) {
    cb(null, true);
  } else {
    cb(new Error(`Invalid file type for ${file.fieldname}`), false);
  }
};

const upload = multer({
  storage: storage,
  fileFilter: fileFilter,
});

// 路由配置
router.get("/", FormCourses.get_FormCourse);

// 使用fields处理多字段文件上传
router.post(
  "/",
  upload.fields([
    { name: 'file', maxCount: 1 },
    { name: 'video', maxCount: 1 },
    { name: 'pdf', maxCount: 1 }
  ]),
  FormCourses.post_FormCourse
);

router.patch("/:courseId", checkAuth, FormCourses.patch_FormCourse);
router.delete("/:delete", checkAuth, FormCourses.delete_FormCourse);

module.exports = router;

2. 修复控制器代码

改用req.files获取各字段的文件路径,同时修正异步操作和必填字段问题:

exports.post_FormCourse = async (req, res, next) => {
  try {
    const FormCourse_id = req.body.FormCourse_id;
    // 异步操作需加await
    const isFormCourse = await FormCourse.findById(FormCourse_id);
    if (!isFormCourse) {
      return res.status(404).json("FormCourse not found");
    }
    
    const course = new FormCourse({
      FormCourse: FormCourse_id, // 模型必填字段赋值
      date: req.body.date,
      file: req.files?.file?.[0]?.path || null,
      video: req.files?.video?.[0]?.path || null,
      pdf: req.files?.pdf?.[0]?.path || null,
    });
    
    const result = await course.save();
    res.status(200).send({
      result: result,
      request: {
        type: "GET",
        url: `http://localhost:3002/form/${result._id}`
      },
    });
  } catch (error) {
    res.status(500).json({ message: "Server error", error: error.message });
  }
};

3. 其他细节修正

  • 视频MIME类型修正为video/*(原配置application/video错误)
  • 错误处理中err变量改为error(原变量未定义)
  • 确保模型必填字段FormCourse被正确赋值

测试说明

Postman测试时选择form-data格式,添加以下字段:

  • 文本字段:date、FormCourse_id
  • 文件字段:file(普通文件)、video(视频文件)、pdf(PDF文件)

内容的提问来源于stack exchange,提问作者Hi Chem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 05:35:25