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

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();

问题分析与修复方案

核心问题点

  1. 单连接导致并发请求阻塞:使用createConnection创建单数据库连接,当多个请求同时到达时,连接会被占用,后续请求会排队等待,导致页面长时间加载甚至卡住。
  2. SQL注入风险+查询稳定性问题:直接拼接SQL字符串,若email包含特殊字符(如')会导致查询失败;同时存在严重的SQL注入风险。
  3. 错误处理不完整: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 17:40:25