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

生成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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:09:35