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

Express登录系统开发遇ReferenceError及Mongoose验证错误求助

登录系统两类错误排查与解决方法

你遇到的这两个错误分别是作用域/异步逻辑问题和Mongoose模型字段验证问题,下面逐个分析原因和解决办法:


一、ReferenceError: sorted is not defined错误

原因分析

  1. 不必要的await导致逻辑混乱:flattenUsers.reduce()是同步数组方法,不需要用await修饰,这会让sorted的赋值变成一个Promise,而非预期的数组结构。
  2. 冗余的数组转换逻辑:你把用户数组先扁平化再还原的操作完全没必要,直接遍历原始users数组即可,额外的转换反而增加了出错概率。
  3. 路由注册的异步依赖隐患:你把路由注册放在User.find的回调内,虽然理论上路由处理函数能访问sorted,但数据库查询是异步操作,若请求在查询完成前到达,就会出现变量未定义的情况;紧凑的代码也容易出现括号配对错误,导致sorted脱离预期作用域。

解决方法

  • 去掉reduce前的await,因为reduce是同步方法;
  • 直接使用users原始数组,删除冗余的扁平化/还原逻辑;
  • 调整路由注册逻辑,不要依赖异步查询结果注册路由,把查询逻辑移到路由处理函数内部。

示例修正后的核心代码:

var express = require('express'); 
const app = express(); 
const User = require('./models/user.js'); 
var _ = require('lodash');
const bcrypt = require('bcrypt'); // 记得引入bcrypt
const jwt2 = require('jsonwebtoken'); // 记得引入jsonwebtoken

// 必须添加这个中间件解析JSON请求体
app.use(express.json());

// 直接注册路由,查询逻辑放在处理函数内
app.post('/api/login', async function (req, res){
  try {
    // 根据请求的用户名/邮箱查询用户
    const user = await User.findOne({ 
      $or: [
        { firstname: req.body.firstname },
        { eMail: req.body.eMail }
      ]
    });

    if (!user) {
      return res.status(401).send("用户不存在");
    }

    // 验证密码是否匹配
    const isPasswordValid = await bcrypt.compare(req.body.password, user.password);
    if (!isPasswordValid) {
      return res.status(401).send("密码错误");
    }

    // 生成JWT令牌
    const token = jwt2.sign(
      { userId: user._id, firstname: user.firstname }, 
      'secrethere', 
      { expiresIn: '15min'}
    );
    res.json({ token });

  } catch (err) {
    res.status(500).send("服务器内部错误");
    console.log(err);
  }
});

二、ValidationError: User validation failed错误

原因分析

你的User模型中firstname和eMail是必填字段(required: true),但当前代码存在两个致命问题:

  1. 字段映射错误:你给firstname赋值的是req.body.username,但Postman请求参数是firstname,导致firstname字段值为undefined;
  2. 核心逻辑颠倒:登录接口的职责是验证已有用户的账号密码,你却在登录时创建新用户,而且完全没有传入eMail参数,触发了Mongoose的必填字段验证。

解决方法

  1. 修正字段映射:如果Postman传参是firstname,就用req.body.firstname赋值,不要用username;
  2. 纠正核心逻辑:删除登录接口中创建User实例的代码,改成查询数据库验证用户的逻辑;
  3. 如果需要注册用户,单独写一个注册接口,确保传入所有必填字段。

示例注册接口的正确写法(若需要):

app.post('/api/register', async function (req, res){
  try {
    const hashedPassword = await bcrypt.hash(req.body.password, 10);
    var user = new User({
      firstname: req.body.firstname,
      eMail: req.body.eMail,
      password: hashedPassword,
      lastname: req.body.lastname || '',
      active: true
    });
    await user.save();
    res.status(201).send("用户注册成功");
  } catch (err) {
    res.status(400).send(err.message);
    console.log(err);
  }
});

额外优化建议

  • 不要把JWT密钥硬编码在代码里,建议用环境变量存储;
  • 错误处理要更细化,返回给前端明确的错误信息,比如“用户名不存在”“密码错误”;
  • 确保所有依赖的包(如bcrypt、jsonwebtoken)都已安装并正确引入。

内容的提问来源于stack exchange,提问作者Munchkin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:08:23