如何在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
相关产品推荐
相关产品推荐

