API的PUT方法无法通过req.body更新User模型money字段问题
PUT接口money字段更新失败问题修复
核心问题点
findOneAndUpdate默认返回更新前的旧文档,不加配置的情况下接口永远返回修改前的数据,很容易误判为更新没生效。- Mongoose Schema默认开启
strict严格模式,传入字段和Schema定义类型不匹配时会被静默过滤,不会写入数据库。当前Schema中money为Number类型,如果测试时传的是字符串格式的数值(比如接口测试工具默认传了文本类型的"300"),该字段会被直接丢弃,不会执行更新。 - Schema存在字段类型错误:
email被定义为SchemaTypes.Number,正常邮箱为字符串格式,目前能更新只是测试时刚好传了数字值、类型匹配才生效。 - 代码存在安全风险:直接把整个
req.body透传给$set,没有做字段白名单限制,用户可以随意篡改luck这类未开放修改的字段。
修复代码
1. 修改PUT接口逻辑
文件路径:/api/[id].ts
case "PUT": try { // 仅提取允许前端修改的字段,禁止直接透传整个req.body const { money, email, name, image } = req.body; const updateData: Record<string, unknown> = {}; // 对字段做类型转换和校验,避免类型不匹配被Mongoose过滤 if (money !== undefined) { const moneyVal = Number(money); if (!isNaN(moneyVal)) updateData.money = moneyVal; } if (email !== undefined) updateData.email = email; if (name !== undefined) updateData.name = name; if (image !== undefined) updateData.image = image; const user = await UserModel.findOneAndUpdate( { _id: id }, { $set: updateData }, { new: true, // 配置返回更新后的新文档,而非更新前的旧数据 runValidators: true // 开启更新操作的Schema校验,拦截非法数据 } ); if (!user) { return res.status(404).json({ success: false, msg: "用户不存在" }); } res.status(200).json(user); } catch (error) { res.status(400).json({ success: false, msg: (error as Error).message }); } break;
2. 修正Schema字段类型
文件路径:models/UserModel.ts
import { model, models, Schema, SchemaTypes } from "mongoose"; const UserSchema = new Schema({ name: { type: SchemaTypes.String, required: true, }, email: { type: SchemaTypes.String, // 修正:邮箱为字符串类型,不是数字 required: false, }, image: { type: SchemaTypes.String, required: true, }, emailVerified: { type: SchemaTypes.Date, // 若存时间戳可保留Number,常规逻辑下邮箱验证状态为时间日期类型 required: false, }, money: { type: SchemaTypes.Number, required: true, default: 100, }, luck: { type: SchemaTypes.Number, required: true, default: 1, }, }); export default models.User || model("User", UserSchema);
验证注意事项
- 接口测试时确认
money参数为数字类型,不要传字符串格式的数值 - 调用接口后返回的是更新后的最新文档,可同步查库确认字段值是否变更
- 不要传未在白名单内的字段,避免非预期更新
内容的提问来源于stack exchange,提问作者FSCYT
相关产品推荐
相关产品推荐

