为什么MongoDB中findOne()无返回值?密码重置路由故障求助
密码重置POST路由问题解决方案
核心问题1:User.findOne()始终返回null
排查和修复步骤:
- 核对字段匹配:先打印
console.log(req.body.username)确认请求携带的参数值是正确的邮箱,再检查User模型定义,确认存储用户邮箱的字段名确实是email,如果模型中邮箱字段名为username或者其他命名,修改查询条件为对应的字段即可 - 确认数据存在且大小写匹配:检查数据库中对应集合的用户数据,确认待查询的邮箱确实存在。部分数据库对字符串查询默认大小写敏感,如果存在大小写不一致的情况,统一转小写后再查询和存储:
// 查询时统一转小写 const user = await User.findOne({ email: req.body.username.toLowerCase() });
- 确认模型配置正确:检查User模型和数据库的连接是否正常,findOne方法是否能正常返回Promise,没有出现模型导入错误、连接异常等问题。
核心问题2:token undefined报错
报错的根本原因是async语法和async.waterfall回调机制混用冲突:你给waterfall的第二个任务函数添加了async关键字,async函数默认会返回Promise,不会自动触发waterfall的done回调,打断了参数传递链,导致后续任务无法拿到正确的token值。
修复方案参考:
方案1:适配async.waterfall 去掉async/await,改用回调写法
function(token, done) { User.findOne({ email: req.body.username }, function(err, user) { if (err) return done(err); if (!user) { req.flash('error', 'No account with that email address exists.'); return res.redirect('/forget-password'); } user.resetPasswordToken = token; user.resetPasswordExpires = Date.now() + 3600000; // 1小时有效期 user.save(function(err) { done(err, token, user); }); }); },
方案2:完全改用async/await语法,弃用async.waterfall
重写后的整体逻辑更简洁,避免回调嵌套问题:
app.post('/check-auth', async (req, res, next) => { try { // 生成token const buf = crypto.randomBytes(20); const token = buf.toString('hex'); // 查询用户 const user = await User.findOne({ email: req.body.username }); if (!user) { req.flash('error', 'No account with that email address exists.'); return res.redirect('/forget-password'); } // 保存重置信息 user.resetPasswordToken = token; user.resetPasswordExpires = Date.now() + 3600000; await user.save(); // 发送邮件 const smtpTransport = nodemailer.createTransport({ service: 'Gmail', auth: { user: 'xyz@gmail.com', pass: 'jvjvsdjfvjdvjdvdv' } }); const mailOptions = { from: 'passwordreset@demo.com', to: req.body.username, subject: 'Node.js Password Reset', text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/reset/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n' }; await smtpTransport.sendMail(mailOptions); req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.'); res.redirect('/forgot'); } catch (err) { next(err); } });
内容的提问来源于stack exchange,提问作者Tushar
相关产品推荐
相关产品推荐

