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

如何在Express.js中以正确数据类型格式接收表单数据

问题:Express接收表单数据类型不符合预期

我有一个包含多种输入类型的表单:

<form action="/listings/create" method="post">
  <fieldset>
    <legend>Informacije o zgradi</legend>
    <div>
      <label for="city">Grad:</label>
      <input type="text" name="city" maxlength="255" required id="city">
    </div>

    <div>
      <label for="street">Ulica:</label>
      <input type="text" name="street" maxlength="255" required id="street">
    </div>

    <div>
      <label for="streetNum">Broj ulice:</label>
      <input type="number" name="streetNum" required id="streetNum">
    </div>

    <div>
      <label for="constructedIn">Izgrađen:</label>
      <input type="number" name="constructedIn" required id="constructedIn">
    </div>

    <div>
      <label for="numOfFloors">Spratnost:</label>
      <input type="number" name="numOfFloors" required id="numOfFloors">
    </div>

    <div>
      <label for="parking">Parking:</label>
      <input type="checkbox" name="parking" id="parking">
    </div>

    <div>
      <label for="garage">Garaža:</label>
      <input type="checkbox" name="garage" id="garage">
    </div>

    <div>
      <label for="elevator">Lift:</label>
      <input type="checkbox" name="elevator" id="elevator">
    </div>

    <div>
      <label for="cctv">Video nadzor:</label>
      <input type="checkbox" name="cctv" id="cctv">
    </div>

    <div>
      <label for="intercom">Interfon:</label>
      <input type="checkbox" name="intercom" id="intercom">
    </div>
  </fieldset>
</form>

当表单数据发送到Express后,所有值都以字符串形式返回,而非预期的数字或布尔值。我需要将这些数据用于Prisma创建条目,试过busboy、multiparty、multer、formidable等工具,但它们大多针对文件上传场景。

我的路由代码:

router.post("/create", async (req, res, _next) => { // /listings/create
  res.status(200).send(req.body);
});

实际返回的结果:

{
  "city": "Novi Sad",
  "street": "Alekse Šantića",
  "streetNum": "4",
  "constructedIn": "2008",
  "numOfFloors": "1",
  "parking": "on",
  "cctv": "on",
  "intercom": "on"
}

预期的结果:

{
  "city": "Novi Sad",
  "street": "Alekse Šantića",
  "streetNum": 4,
  "constructedIn": 2008,
  "numOfFloors": 1,
  "parking": true,
  "garage": false,
  "elevator": false,
  "cctv": true,
  "intercom": true
}

我尝试过使用formidable,但网站加载超时,对应的路由代码:

router.post("/create", async (req, res, next) => {
  const form = formidable({});

  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }

    res.json({ fields, files });
  });
});

解决方案

1. 正确配置Express的urlencoded中间件

默认的express.urlencoded不会自动转换数字类型,先确保你的Express应用已配置基础中间件:

import express from 'express';
const app = express();

// 配置urlencoded中间件,支持复杂对象解析
app.use(express.urlencoded({ extended: true }));

2. 手动转换数据类型

HTTP表单提交的所有值本质都是字符串(复选框选中时为"on",未选中则不会出现在req.body中),需要手动转换为目标类型:

router.post("/create", async (req, res) => {
  const parsedBody = {
    ...req.body,
    // 转换数字字段
    streetNum: parseInt(req.body.streetNum, 10),
    constructedIn: parseInt(req.body.constructedIn, 10),
    numOfFloors: parseInt(req.body.numOfFloors, 10),
    // 处理复选框:存在则为true,否则补全false
    parking: req.body.parking === "on",
    garage: req.body.garage === "on",
    elevator: req.body.elevator === "on",
    cctv: req.body.cctv === "on",
    intercom: req.body.intercom === "on"
  };

  // 此处可调用Prisma创建条目
  // await prisma.listing.create({ data: parsedBody });

  res.status(200).send(parsedBody);
});

3. 使用Schema验证库简化转换(可选)

如果字段较多,可借助Zod、Joi等库实现自动类型转换与验证,以Zod为例:

import { z } from 'zod';

// 定义数据Schema
const ListingSchema = z.object({
  city: z.string().max(255),
  street: z.string().max(255),
  streetNum: z.coerce.number(),
  constructedIn: z.coerce.number(),
  numOfFloors: z.coerce.number(),
  parking: z.boolean().default(false),
  garage: z.boolean().default(false),
  elevator: z.boolean().default(false),
  cctv: z.boolean().default(false),
  intercom: z.boolean().default(false)
});

router.post("/create", async (req, res) => {
  // 转换并验证数据
  const parsedBody = ListingSchema.parse({
    ...req.body,
    parking: req.body.parking === "on",
    garage: req.body.garage === "on",
    elevator: req.body.elevator === "on",
    cctv: req.body.cctv === "on",
    intercom: req.body.intercom === "on"
  });

  // 后续业务操作
  res.status(200).send(parsedBody);
});

关于formidable的问题

formidable超时大概率是因为表单enctype未匹配或中间件冲突,若无需文件上传,完全没必要使用这类工具,Express自带的urlencoded中间件足够满足需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:19:55