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

Node.js+PostgreSQL登录接口查询返回空rows问题排查

用户登录接口查询返回空数组问题

问题表现

  • 服务启动无报错,日志如下:
[nodemon] restarting due to changes...
[nodemon] starting `node server.js`
Example app listening on port 8080
Connected to database
  • 接口能正常接收到请求体 { username: 'torontofam', password: 'password' },但数据库查询返回rowCount: 0、rows: [],仅返回表字段元信息:
result{
  command: 'SELECT',
  rowCount: 0,
  oid: null,
  rows: [],
  fields: [
    Field {
      name: 'id',
      tableID: 19247,
      columnID: 1,
      dataTypeID: 23,
      dataTypeSize: 4,
      dataTypeModifier: -1,
      format: 'text'
    },
    Field {
      name: 'username',
      tableID: 19247,
      columnID: 2,
      dataTypeID: 1043,
      dataTypeSize: -1,
      dataTypeModifier: 259,
      format: 'text'
    },
    Field {
      name: 'password',
      tableID: 19247,
      columnID: 3,
      dataTypeID: 1043,
      dataTypeSize: -1,
      dataTypeModifier: 259,
      format: 'text'
    },
  ]
}
  • 手动在psql客户端执行带bcrypt哈希密码的查询语句,能正常查到1条匹配记录:
midterm=# SELECT * FROM users WHERE username = 'torontofam' AND password = '$2a$10$FB/BOAVhpuLvpOREQVmvmezD4ED/.JBIDRh70tGevYzYzQgFId2u.';;
 id |  username  |                           password                           |  latitude  |  longitude  
----+------------+--------------------------------------------------------------+------------+-------------
  1 | torontofam | $2a$10$FB/BOAVhpuLvpOREQVmvmezD4ED/.JBIDRh70tGevYzYzQgFId2u. | 43.6523736 | -79.3857858
(1 row)
  • 发起登录请求后接口返回400,响应信息为 POST /api/users/login 400 26.831 ms - 44 {"message":"Username not found in database"}

原有问题代码

router.post("/login", (req, res) => {
const { username, password } = req.body;
console.log(req.body);
const queryString = `SELECT * FROM users WHERE username = $1 AND password = $2;`;
db.query(queryString, [username, password])
  .then((data) => {
    console.log(data);
    const user = data.rows[0];

    if (!user) {
      return res
        .status(400)
        .send({ message: "Username not found in database" });
    }

    const validPassword = bcrypt.compareSync(password, user.password);

    if (!validPassword) {
      return res
        .status(400)
        .send({ message: "Password does not match username" });
    }
    req.session.user_id = user.id;
    res.redirect("/");
  })
  .catch((err) => {
    res.status(500).json({ error: err.message });
  });
});

问题原因

你完全用错了bcrypt的校验流程:

  • 数据库里存的password字段是bcrypt生成的哈希串,不是明文
  • 你当前的SQL逻辑是拿前端传的明文密码password,直接和库里存的60位哈希串做等值匹配,两个值根本不相等,自然查不到任何记录
  • 你在psql里能查到结果,是因为手动把哈希值写进了查询条件,和接口传明文参数的逻辑完全不一样
  • 补充:bcrypt加密时自带随机盐,同一个明文每次生成的哈希值都不同,本身就不支持在SQL层做密码等值匹配。

修复方案

查询阶段只通过用户名匹配用户记录,拿到用户存储的哈希密码后,再用bcrypt的compare方法做密码校验,修正后代码如下:

router.post("/login", (req, res) => {
const { username, password } = req.body;
console.log(req.body);
// 去掉SQL里的密码等值判断,仅按用户名查询
const queryString = `SELECT * FROM users WHERE username = $1;`;
db.query(queryString, [username])
  .then((data) => {
    console.log(data);
    const user = data.rows[0];

    if (!user) {
      return res
        .status(400)
        .send({ message: "Username not found in database" });
    }

    // 对比明文密码和数据库存储的哈希密码
    const validPassword = bcrypt.compareSync(password, user.password);

    if (!validPassword) {
      return res
        .status(400)
        .send({ message: "Password does not match username" });
    }
    req.session.user_id = user.id;
    res.redirect("/");
  })
  .catch((err) => {
    res.status(500).json({ error: err.message });
  });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:30:57