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

PostgreSQL+Node.js+Express连接代码修正及POST请求问题排查

解决Postman POST请求的两个核心问题(Node.js/Express/PostgreSQL)

让我们一步步拆解并解决你遇到的这两个问题:


问题1:username存入数据库为null的原因及修复

首先看你的代码,根本原因是变量名错误,和关联用户表无关,具体问题出在这几处:

  1. 你构造data对象时,把req.body.username赋值给了author字段,但后续插入时却用了data.username——这个属性根本不存在,所以会传入null!
  2. 第一个INSERT语句返回的是id(你写的RETURNING id),但你后面却用了res.rows[0].pid,这里应该是res.rows[0].id,否则也会导致pid字段错误甚至插入失败。
  3. created_on字段你传了字符串'now()',PostgreSQL会把它当成普通字符串存储,而不是当前时间,应该直接用NOW()(不带引号)或者new Date()。

修复后的核心代码片段(原回调版本):

// 第一个查询修复获取id
db.query(query, ['value1', new Date()], (err, table1Res) => {
  if (shouldAbort(err)) return;
  const data = {
    author: req.body.username, // 这里是author
    title: req.body.title,
    // ...其他字段
  };
  const insertPostValues = [
    table1Res.rows[0].id, // 用id代替pid
    data.author, // 用data.author代替data.username
    data.title,
    // ...其他字段
    NOW() // 不带引号,或者用new Date()
  ];
  // ...后续代码
});

问题2:请求一直处于发送状态的原因及async/await重构

你的请求一直挂起,是因为整个函数没有调用res.send()/res.json()来结束响应,而且回调嵌套太深,很容易遗漏错误处理和响应逻辑。另外,原有的事务处理如果出错,也没有回滚和返回错误信息。

下面是改用async/await的完整重构方案,代码更清晰,逻辑更可靠:

第一步:重构数据库连接文件 db/index.js

将原有的回调风格改成Promise/async支持的版本:

const { Pool } = require('pg')
const pool = new Pool({
  user: '', // 填入你的数据库用户名
  host: 'localhost',
  database: '', // 填入你的数据库名
  password: '', // 填入你的数据库密码
  port: 5432 // PostgreSQL默认端口,根据你的配置修改
})

// 封装async版query方法
const query = async (text, params) => {
  const start = Date.now()
  const res = await pool.query(text, params)
  const duration = Date.now() - start
  console.log('executed query', { text, duration, rows: res.rowCount })
  return res
}

// 封装async版getClient方法(用于事务)
const getClient = async () => {
  const client = await pool.connect()
  const originalQuery = client.query
  const timeout = setTimeout(() => {
    console.error('客户端已被占用超过5秒!')
    console.error('最后执行的查询:', client.lastQuery)
  }, 5000)

  // 猴子补丁追踪最后执行的查询
  client.query = (...args) => {
    client.lastQuery = args
    return originalQuery.apply(client, args)
  }

  // 封装释放客户端的逻辑
  const release = () => {
    clearTimeout(timeout)
    client.query = originalQuery
    client.release()
  }

  return { client, release }
}

module.exports = { query, getClient }

第二步:重构路由处理函数 router/routefile.js

改成async函数,完善事务处理和响应逻辑:

exports.addKeyword = async (req, res) => {
  let dbClient;
  try {
    // 获取客户端用于事务操作
    const { client, release } = await db.getClient();
    dbClient = client;

    // 开启事务
    await dbClient.query('BEGIN');

    // 第一步插入Table1,获取返回的id
    const table1Query = 'INSERT INTO Table1 (post_type, created_on) VALUES($1, $2) RETURNING id';
    const table1Result = await dbClient.query(table1Query, ['value1', new Date()]);
    const table1Id = table1Result.rows[0].id;

    // 构造要插入的数据
    const data = {
      author: req.body.username,
      title: req.body.title,
      description: req.body.description,
      body: req.body.body,
      category: req.body.category,
      search_volume: req.body.search_volume,
      is_deleted: req.body.is_deleted || false // 给默认值避免null
    };

    // 插入m_keyword的SQL语句
    const insertPostText = `
      INSERT INTO m_keyword (
        pid, author, title, description, body, category, search_volume, is_deleted, created_on
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW())
    `;
    const insertPostValues = [
      table1Id,
      data.author,
      data.title,
      data.description,
      data.body,
      data.category,
      data.search_volume,
      data.is_deleted
    ];

    // 执行插入
    await dbClient.query(insertPostText, insertPostValues);

    // 提交事务
    await dbClient.query('COMMIT');

    // 返回成功响应,结束请求
    res.status(201).json({
      success: true,
      message: '记录创建成功!',
      pid: table1Id
    });
  } catch (err) {
    // 出错时回滚事务
    if (dbClient) {
      await dbClient.query('ROLLBACK');
    }
    console.error('事务处理失败:', err.stack);
    // 返回错误响应,结束请求
    res.status(500).json({
      success: false,
      message: '创建记录失败',
      error: err.message
    });
  } finally {
    // 无论成功失败,都释放客户端回连接池
    if (dbClient) {
      dbClient.release();
    }
  }
};

关键改进点:

  1. 用async/await替代回调嵌套,代码可读性和可维护性大幅提升;
  2. 确保在成功和失败场景下都调用res.json()返回响应,不会让请求一直挂起;
  3. 完善的事务处理:出错时自动回滚,避免脏数据;
  4. 添加了默认值(比如is_deleted: req.body.is_deleted || false),减少意外的null值;
  5. 用new Date()或NOW()正确处理时间字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:01:17