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

Node.js中间件中无法获取req.body:返回空值问题排查

Express中带文件上传请求的req.body为空问题排查与解决

在Node.js Express应用的userExists中间件中访问req.body时始终得到空值,但请求确实包含邮箱、密码等数据。已完成以下检查:

  • 解析请求体的中间件(body-parser)已置于目标中间件之前
  • 配置了bodyParser.json()和urlencoded,且请求Content-Type与配置匹配
  • 确认请求体数据完整,并非空请求

需求说明:先检查邮箱是否已存在、密码是否匹配,校验不通过则不上传图片到云端;校验通过后再完成文件上传和用户注册。


代码片段

userExists.js

const User = require("../Model/userSchema");

const userExists = async (req, res, next) => {
  const { email, password, confirmPassword } = req.body;

  console.log(req.body);

  console.log("email:", email);
  console.log("password:", password);
  console.log("confirmPassword:", confirmPassword);

  const emailExist = await User.findOne({ email });
  if (emailExist) {
    return res.status(400).send({ message: "Email Id already exists" });
  }

  if (password !== confirmPassword) {
    return res.status(400).send({ message: "Passwords do not match" });
  }

  next();
};

module.exports = userExists;

index.js

const express = require("express");
const dotenv = require("dotenv");
const cors = require("cors");
const connectDB = require("./db/db");
const authRoutes = require("./routes/user");
const bodyParser = require("body-parser");
const multer = require("multer");
const { storage } = require("./config/storage");
const { register } = require("./controllers/user");
const userExists = require("./middleware/userExist");

const app = express();

dotenv.config();

const port = process.env.PORT || 5001;

//middlewares
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
const upload = multer({ storage });

//routes
app.use("/api/auth", authRoutes);

//routes with files
app.post("/api/auth/register", userExists, upload.single("file"), register);

connectDB();

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

问题根源

核心原因是带文件的请求使用multipart/form-data格式,而body-parser无法解析该类型的请求体:

  • 当请求包含文件时,前端必须使用multipart/form-data作为Content-Type,但bodyParser.json()和bodyParser.urlencoded()仅支持application/json、application/x-www-form-urlencoded格式,对multipart/form-data无效。
  • 当前路由中间件顺序是userExists在前、upload.single("file")在后,multer未执行时请求体未被解析,因此req.body为空。

若直接调整顺序让upload.single("file")在前,虽能拿到req.body,但会先将文件上传到云端存储,不符合“先校验再上传”的需求。


解决方案

采用multer内存存储+手动上传的方式,先将文件暂存到内存中,完成校验后再上传到云端,校验不通过则直接丢弃内存中的文件:

步骤1:修改multer配置为内存存储

// 替换原multer配置
const multer = require("multer");
// 文件暂存到内存,内容会存在req.file.buffer中
const storage = multer.memoryStorage();
const upload = multer({ storage });

步骤2:调整路由中间件顺序

必须让multer先解析请求体,userExists才能拿到完整的req.body:

app.post("/api/auth/register", upload.single("file"), userExists, register);

步骤3:修改register控制器,手动上传文件到云端

在register函数中,校验通过后再将内存中的文件上传到云端,示例伪代码:

const register = async (req, res) => {
  try {
    // 获取用户信息与文件数据
    const { email, password } = req.body;
    const file = req.file;
    
    // 手动上传文件到云端(替换为你的云端上传逻辑)
    const uploadResult = await cloudStorage.upload(file.buffer, {
      filename: file.originalname,
      contentType: file.mimetype
    });

    // 创建用户记录并保存文件地址
    const newUser = new User({
      email,
      password: await bcrypt.hash(password, 10),
      avatar: uploadResult.url
    });
    await newUser.save();

    res.status(201).send({ message: "User registered successfully" });
  } catch (err) {
    res.status(500).send({ message: "Server error", error: err.message });
  }
};

额外注意事项

  • 前端需确保请求的Content-Type为multipart/form-data,且正确附加文本字段(email、password、confirmPassword)和文件。
  • 若文件体积较大,内存存储可能导致内存占用过高,可改用临时文件存储,校验通过后移动到云端,不通过则删除临时文件。

内容的提问来源于stack exchange,提问作者Md Adil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 22:10:02