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

Express用户登录报错"Illegal arguments: string, undefined"

错误原因

接口返回Illegal arguments: string, undefined是bcrypt.compare()接收到的第二个参数(数据库存储的哈希密码)为undefined导致,核心问题出在用户模型定义:

  • userSchema中重复声明了两次name字段,原本用于存储密码的字段被错误命名为name,整个Schema根本没有定义password字段
  • 这导致注册用户时,MongoDB中存储的用户文档不会包含password属性,查询返回的用户对象上user.password值为undefined,传入bcrypt做密码比对时直接触发参数类型错误
  • 现有登录逻辑还存在两个潜在问题:未校验请求体是否携带邮箱、密码参数;登录失败返回404状态码不符合HTTP语义。
修复步骤

1. 修正用户模型定义

把重复的name字段改为password字段,同时补充密码哈希前置钩子,确保数据库存的是哈希后的密码而非明文:

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = mongoose.Schema({
    name: {
        type: String,
        required: [true, 'please add a name']
    },
    email: {
        type: String,
        required: [true, 'please add an email'],
        unique: true
    },
    // 修正:原此处错误写为name,改为password
    password: {
        type: String,
        required: [true, 'please add a password']
    },
},{
    timestamps:true
})

// 新增:保存用户前自动哈希密码
userSchema.pre('save', async function(next) {
    if (!this.isModified('password')) {
        next()
    }
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
})

module.exports = mongoose.model('User', userSchema)

注意:模型修改完成后,需要删除之前创建的所有旧测试用户数据。旧数据因为模型定义错误没有存储password字段,即使修复代码后查询旧数据依然会出现password为undefined的问题,删除后重新走注册流程创建新用户即可。

2. 优化登录接口逻辑

增加入参校验,调整错误状态码:

const bcrypt = require('bcryptjs');
const asyncHandler = require('express-async-handler');
const User = require('../model/userModel');

const loginUser = asyncHandler(async(req, res) => {
    const {email, password} = req.body;

    // 新增:校验入参完整性
    if (!email || !password) {
        res.status(400)
        throw new Error('Please provide email and password')
    }

    // 根据邮箱查询用户
    const user = await User.findOne({ email })

    // 用户存在且密码比对通过时返回用户信息
    if(user && (await bcrypt.compare(password, user.password))){
        res.json({
            _id: user.id,
            name: user.name,
            email: user.email, 
        })
    }else{
        // 修正:认证失败返回401状态码,符合HTTP语义
        res.status(401)
        throw new Error('Invalid email or password!')
    }
})
  • 移除了password.toString()调用:正常请求传入的password本身就是字符串类型,加toString()在password为undefined时反而会触发额外报错,提前做入参校验比调用toString()更稳妥。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 19:06:43