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

使用Multer按用户指定文件名存文件异常:始终用默认名称

问题描述

我在Express中集成Multer实现文件上传,希望按照前端传入的filename参数保存文件,但实际总是用默认名称存储。在multer.diskStorage的filename回调(标记为place2处)中打印req.body.filename显示undefined,req.body是空对象;但在/upload路由处理函数中却能获取到正确的req.body。请问这一现象的原因是什么?

const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const multer = require("multer");
const path = require("path");

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
const app = express();

app.use(cors());
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded bodies for form data
mongoose.connect("mongodb://127.0.0.1:27017/Gallary");

const schema = new mongoose.Schema({
  email: {
    required: true,
    type: String,
  },
  password: {
    required: true,
    type: String,
  },
});
const Login = mongoose.model("Login", schema);

app.get("/", (req, res) => {
  res.send("Gallery it is");
});

app.post("/SignUp", async (req, res) => {
  try {
    let result = await Login.find(req.body);
    if (result.length == 0) {
      let data = new Login(req.body);
      await data.save();
      res.send({ result: true });
    } else {
      res.send({ result: false });
    }
  } catch (e) {
    res.send(e);
  }
});

app.post("/Login", async (req, res) => {
  try {
    let result = await Login.find(req.body);
    console.log("came");
    if (result.length != 0) {
      res.send({ result: true });
    } else {
      res.send({ result: false });
    }
  } catch (e) {
    res.send({ result: false });
  }
});

// Define multer storage configuration
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "uploads/");
  },
  filename: (req, file, cb) => {
    console.log("place2"+req.body.filename );
    const filename = req.body.filename ? req.body.filename : `default_filename_${Date.now()}${path.extname(file.originalname)}`;
    cb(null, filename);
  },
});

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

// Define route for image upload
app.post("/upload", upload.single("image"), (req, res) => {
  console.log("Uploaded file:", req.file.filename);
  res.json({ filename: req.file.filename });
});

app.listen(process.env.PORT || 3001, () => {
  console.log("Server is running on port 3001");
});
原因分析及解决方案

核心原因

Multer处理文件上传的时机早于Express的express.urlencoded()中间件解析请求体的时机。

当前端发送multipart/form-data类型的请求时,请求体里的普通字段(比如filename)和文件数据是混合传输的。Multer在解析文件阶段会先读取文件部分,此时Express的express.urlencoded()还没开始解析普通表单字段,所以在filename回调里req.body还没被填充,自然拿不到filename参数。而进入路由处理函数时,Multer已经完成了整个请求体的解析(包括普通字段),所以此时req.body是完整的。

解决方案

Multer本身会自动解析multipart/form-data请求里的普通字段并填充到req.body中,不需要依赖express.urlencoded()(它只负责解析application/x-www-form-urlencoded类型的请求)。只需注意:

  • 前端用FormData发送数据时,先添加普通字段,再添加文件。比如:
// 前端示例代码
const formData = new FormData();
formData.append('filename', '自定义文件名.jpg'); // 先传普通字段
formData.append('image', file); // 后传文件

这样Multer在解析文件前会先解析前面的filename字段,此时req.body.filename就能在filename回调中正常获取到了。

后端的express.urlencoded()可以保留,用于处理其他非文件上传的表单请求,不会影响Multer的工作。

内容的提问来源于stack exchange,提问作者Pratham Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:25:20