Node.js异步登录系统异常:页面反复加载无法登录
问题:登录系统页面持续反复加载,偶尔能正常登录
使用Node.js和MySQL开发登录系统,结合async/await和Promise使用时出现异常:系统无报错,但页面持续反复加载,用户无法完成登录;偶尔又能正常登录。怀疑await使用或数据库连接的.promise()方法存在问题,相关代码如下:
用户登录代码块
exports.login = async (req, res) => { try { const { email, password } = req.body; // if (!email || !password) { // return res.status(400).render("giriş_yap", { // msg: "Lütfen e-mail veya şifrenizi giriniz", // msg_type: "error", // }); // } const allDB = await login_db.query(`select * from users where email='${email}'`); const user = allDB[0] ; //console.log(user[0]) ; if (user.length <= 0) { return res.status(401).render("giriş_yap", { msg: "Sistemde kaydınız bulunamadı", msg_type: "error", }); } else { const passwordMatch = (await bcrypt.compare(password, user[0].PASS)) if (!passwordMatch) { return res.status(401).render("giriş_yap", { msg: "Emailiniz veya Şifreniz hatalı", msg_type: "error", }); } else { const id = user[0].ID; const token =jwt.sign({ id: id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRES_IN, }); //console.log("The Token is " + token); const cookieOptions = { expires: new Date( Date.now() + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000 ), httpOnly: true, }; res.cookie("joes", token, cookieOptions); res.status(200).redirect("/anasayfa"); } } } catch (error) { console.log(error); } };
MySQL数据库连接代码块
const mySql = require("mysql2"); const config = require("../config_db"); const login_db = mySql.createConnection(config.db_login); login_db.connect(function (err) { if (err) { console.log(err); } console.log("Kullanici bilgileri veritabanina başariyla baglandiniz."); }); module.exports = login_db.promise();
问题分析与修复方案
核心问题点
- 单连接导致并发请求阻塞:使用
createConnection创建单数据库连接,当多个请求同时到达时,连接会被占用,后续请求会排队等待,导致页面长时间加载甚至卡住。 - SQL注入风险+查询稳定性问题:直接拼接SQL字符串,若email包含特殊字符(如
')会导致查询失败;同时存在严重的SQL注入风险。 - 错误处理不完整:catch块仅打印错误但未给客户端返回响应,导致请求一直处于挂起状态,客户端可能反复重试,表现为页面持续加载。
修改后的代码
数据库连接(改用连接池)
const mySql = require("mysql2"); const config = require("../config_db"); // 使用连接池替代单连接,自动管理连接生命周期 const login_db = mySql.createPool(config.db_login).promise(); // 连接池无需手动调用connect,会自动处理连接 module.exports = login_db;
登录逻辑(修复查询与错误处理)
exports.login = async (req, res) => { try { const { email, password } = req.body; // 恢复参数校验,避免无效请求进入数据库查询 if (!email || !password) { return res.status(400).render("giriş_yap", { msg: "Lütfen e-mail veya şifrenizi giriniz", msg_type: "error", }); } // 使用参数化查询,避免SQL注入,同时兼容特殊字符 const [user] = await login_db.query('select * from users where email = ?', [email]); if (user.length <= 0) { return res.status(401).render("giriş_yap", { msg: "Sistemde kaydınız bulunamadı", msg_type: "error", }); } const passwordMatch = await bcrypt.compare(password, user[0].PASS); if (!passwordMatch) { return res.status(401).render("giriş_yap", { msg: "Emailiniz veya Şifreniz hatalı", msg_type: "error", }); } const id = user[0].ID; const token = jwt.sign({ id: id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRES_IN, }); const cookieOptions = { expires: new Date( Date.now() + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000 ), httpOnly: true, }; res.cookie("joes", token, cookieOptions); res.status(200).redirect("/anasayfa"); } catch (error) { console.log(error); // 给客户端返回错误响应,避免请求挂起 return res.status(500).render("giriş_yap", { msg: "Sistemde bir hata oluştu", msg_type: "error", }); } };
关键修改说明
- 连接池替代单连接:连接池会维护多个数据库连接,并发请求时自动分配空闲连接,避免请求排队阻塞。
- 参数化查询:通过
?占位符传递参数,mysql2会自动处理转义,避免SQL注入和特殊字符导致的查询失败。 - 完善错误响应:catch块中返回500状态码和错误提示,确保客户端收到响应,不会一直等待导致页面反复加载。
- 恢复参数校验:提前拦截空参数请求,减少无效数据库查询,提升系统稳定性。
内容的提问来源于stack exchange,提问作者Tolkienist Coder
相关产品推荐
相关产品推荐

