生成OTP路由报错:Cannot set property 'mobileNo' of null 求助排查
解决TypeError: Cannot set property 'mobileNo' of null 及OTP生成路由的问题
咱们先来看你遇到的核心报错:TypeError: Cannot set property 'mobileNo' of null,这个问题出在当Account.findOne找不到匹配的手机号时,account变量是null,你却直接尝试给null的属性赋值,这肯定会报错。除此之外,你的代码还有几个其他问题需要一起修正,包括TTL配置错误、变量未定义、参数获取混淆等,下面一步步来解决:
1. 修正Schema的TTL配置
你当前把TTL的配置写在了OtpNo字段里,这是错误的用法。MongoDB的TTL索引需要基于一个日期类型的字段,我们需要单独添加createdAt字段,然后配置索引让文档在指定时间后自动过期:
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var AccountSchema = new Schema({ mobileNo: { type: String, required: true, unique: true }, OtpNo: { type: String, required: true }, createdAt: { type: Date, default: Date.now, index: { expires: 360 } // 设置360秒后自动过期,也就是你要的TTL } }); module.exports = mongoose.model('account', AccountSchema);
2. 修复路由逻辑中的核心问题
核心错误修复:处理null的情况
当找不到账户时,你需要创建一个新的Account实例,而不是直接给null赋值。同时还要解决以下问题:
- 生成随机4位OTP的逻辑缺失
newAccount变量未定义- 混淆了
req.params和req.body的参数获取(你的路由是/:mobileNo,所以手机号在req.params里) - 未处理
findOne的错误 - 已存在账户时,应该更新现有文档而不是重新创建
修正后的路由代码:
router.route('/generateOtp/:mobileNo').get(function (req, res) { const mobileNo = req.params.mobileNo; // 生成4位随机OTP验证码 const otp = Math.floor(1000 + Math.random() * 9000).toString(); Account.findOne({ mobileNo: mobileNo }, function (err, account) { // 先处理数据库查询错误 if (err) { return res.status(500).send({ error: '数据库查询失败', details: err }); } if (!account) { // 账户不存在,创建新实例 const newAccount = new Account({ mobileNo: mobileNo, OtpNo: otp // createdAt会自动用默认值Date.now }); newAccount.save(function (saveErr) { if (saveErr) { return res.status(500).send({ error: '保存账户失败', details: saveErr }); } console.log("新账户已添加并生成OTP"); res.send({ message: 'OTP已生成' }); // 实际项目中不要返回OTP,这里只是示例 }); } else { // 账户已存在,更新OTP和createdAt(重置过期时间) account.OtpNo = otp; account.createdAt = Date.now(); // 重置过期时间,让OTP重新开始计时 account.save(function (saveErr) { if (saveErr) { return res.status(500).send({ error: '更新OTP失败', details: saveErr }); } console.log("已更新现有账户的OTP"); res.send({ message: 'OTP已重新生成' }); // 实际项目中不要返回OTP }); } }); });
额外优化建议
- 建议把请求方法改成
POST,因为生成OTP属于修改数据的操作,GET方法更适合查询类操作 - 实际项目中不要在响应里返回OTP,应该通过短信/邮件等方式发送给用户
- 可以考虑用
findOneAndUpdate来简化代码,不管账户是否存在都能统一处理,比如:
Account.findOneAndUpdate( { mobileNo: mobileNo }, { OtpNo: otp, createdAt: Date.now() }, { upsert: true, new: true }, function (err, account) { if (err) { return res.status(500).send(err); } console.log(account ? "OTP已更新" : "新账户创建并生成OTP"); res.send({ message: 'OTP生成成功' }); } );
内容的提问来源于stack exchange,提问作者user2276821
相关产品推荐
相关产品推荐

