NodeJS+MySQL注册功能误判邮箱/用户名已存在问题排查
NodeJS + MySQL 用户注册校验异常问题
我正在开发基于NodeJS和MySQL的用户注册功能,需求是校验邮箱和用户名是否已存在于系统中,若存在则提示对应信息,不存在则允许注册。但实际测试时,即便数据库中无对应邮箱或用户名,系统仍提示“Email already exists”或“Username already exists”。
注册功能代码
const bcrypt = require("bcryptjs"); const avatars = require("../databases/avatar.js"); const mysqlConnection = require("../databases/connect-mysql.js"); const jwt = require("jsonwebtoken"); const otpGenerator = require("otp-generator"); function getRandomAvatar() { const randomIndex = Math.floor(Math.random() * avatars.length); return avatars[randomIndex].avatar; } async function register(req, res) { try { const { USERNAME, EMAIL, PASSWORD, FIRST_NAME, LAST_NAME } = req.body; if (!EMAIL) { return res.status(400).send("Email cannot be empty"); } // 校验邮箱是否已存在 const emailExistQuery = `SELECT * FROM USERS WHERE EMAIL = ?`; const emailAlreadyExists = await mysqlConnection.query(emailExistQuery, [ EMAIL, ]); if (emailAlreadyExists.length > 0) { return res.status(400).send("Email already exists"); } // 校验用户名是否已存在 const usernameExistQuery = `SELECT * FROM USERS WHERE USERNAME = ?`; const usernameAlreadyExists = await mysqlConnection.query( usernameExistQuery, [USERNAME] ); if (usernameAlreadyExists.length > 0) { return res.status(400).send("Username already exists"); } const salt = bcrypt.genSaltSync(10); const hashedPassword = await bcrypt.hash(PASSWORD, salt); const insertUserQuery = ` INSERT INTO users (USERNAME, EMAIL, PASSWORD, AVATAR, FIRST_NAME, LAST_NAME) VALUES (?, ?, ?, ?, ?, ?)`; const newUserValues = [ USERNAME, EMAIL, hashedPassword, getRandomAvatar(), FIRST_NAME, LAST_NAME, ]; await mysqlConnection.query(insertUserQuery, newUserValues); return res.status(200).send("User has been created"); } catch (error) { return res.status(500).send({ error: error.message }); } }
MySQL表结构
CREATE TABLE USERS ( ID CHAR(36) DEFAULT (UUID()) PRIMARY KEY, USERNAME VARCHAR(255) UNIQUE NOT NULL, EMAIL VARCHAR(255) UNIQUE NOT NULL, PASSWORD VARCHAR(255), EMAIL_VERIFY BOOL DEFAULT FALSE, ADMIN BOOL DEFAULT FALSE, FIRST_NAME VARCHAR(255), LAST_NAME VARCHAR(255), DATE_OF_BIRTH DATE, MOBILE VARCHAR(255), ADDRESS TEXT, AVATAR TEXT, CREATE_AT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UPDATE_AT DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
测试相关截图
- Postman请求截图:

- 数据库截图:

问题原因
你使用的MySQL驱动(大概率是mysql2)在promise模式下执行query方法时,返回的是包含两个元素的数组:第一个元素是查询结果集,第二个是字段元数据。当数据库中没有匹配的邮箱/用户名时,返回的数组结构为[[], fields],此时emailAlreadyExists.length的值是2,大于0,错误触发了“已存在”的提示。
修复方案
修改校验逻辑,提取返回数组中的第一个元素(实际查询结果)来判断长度:
// 邮箱校验逻辑修改 const [emailResult] = await mysqlConnection.query(emailExistQuery, [EMAIL]); if (emailResult.length > 0) { return res.status(400).send("Email already exists"); } // 用户名校验逻辑修改 const [usernameResult] = await mysqlConnection.query(usernameExistQuery, [USERNAME]); if (usernameResult.length > 0) { return res.status(400).send("Username already exists"); }
额外优化
为提升查询性能,可将校验语句改为仅查询存在性,无需返回所有字段:
SELECT 1 FROM USERS WHERE EMAIL = ? LIMIT 1
SELECT 1 FROM USERS WHERE USERNAME = ? LIMIT 1
内容的提问来源于stack exchange,提问作者hellosdfsf
相关产品推荐
相关产品推荐

