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

Node.js+PostgreSQL数据获取失败:TypeError及Axios报错求助

问题排查:Node.js + PostgreSQL费用管理接口数据无法获取错误

问题情况

调用接口时出现错误:Failed to retrieve expenses: TypeError: Cannot read properties of undefined (reading 'json'),同时前端提交表单时触发Axios错误,首次使用PostgreSQL,怀疑数据库连接或代码逻辑存在问题。

现有代码配置

index.js

const express = require('express')

const app = express()

const port = 8000
const expense_model = require('./expense_model')

app.use(express.json());
app.use(function (req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000');
    res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Access-Control-Allow-Headers');
    next();
  });

  app.get('/', (req, res) => {
    expense_model.getExpenses()
      .then(expenses => {
        res.status(200).json(expenses);
      })
      .catch(error => {
        console.error('Failed to retrieve expenses:', error);
        res.status(500).json({ error: 'Failed to retrieve expenses' });
      });
  });
  
  app.post('/expenses', (req, res) => {
    expense_model.createExpense(req.body)
    .then(response => {
      res.status(200).send(response);
    })
    .catch(error => {
      res.status(500).send(error);
    })
  })
  app.delete('/expenses/:id', (req, res) => {
    expense_model.deleteExpense(req.params.id)
    .then(response => {
      res.status(200).send(response);
    })
    .catch(error => {
      res.status(500).send(error);
    })
  })

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

expense_model.js

const Pool = require('pg').Pool
const pool = new Pool({
    user: 'my_user',
    host: 'localhost',
    database: 'my_database',
    password: 'root',
    port: 5432,
  });
 
  async function getExpenses(req, res) {
    try {
      const query = 'SELECT * FROM expenses';
      const result = await pool.query(query);
  
      const expenses = result.rows;
  
      res.status(200).json(expenses);
      console.log('Response:', res);
    } catch (err) {
      console.error('Failed to retrieve expenses:', err);
      res.status(500).json({ error: 'Failed to retrieve expenses' });
    }
  }
  
  async function createExpense(req, res) {
    const { expense, amount, description, tag } = req.body;
    const query = 'INSERT INTO expenses (expense, amount, description, tag) VALUES ($1, $2, $3, $4) RETURNING *';
    const values = [expense, amount, description, tag];
  
    try {
      const result = await pool.query(query, values);
      res.status(201).json(result.rows[0]);
    } catch (err) {
      console.error('Failed to create an expense:', err);
      res.status(500).json({ error: 'Failed to create an expense' });
    }
  }
  
  async function updateExpense(req, res) {
    const id = parseInt(req.params.id);
    const { expense, amount, description, tag } = req.body;
    const query = 'UPDATE expenses SET expense = $1, amount = $2, description = $3, tag = $4 WHERE id = $5';
    const values = [expense, amount, description, tag, id];
  
    try {
      const result = await pool.query(query, values);
      if (result.rowCount === 0) {
        res.status(404).json({ error: 'Expense not found' });
      } else {
        res.json({ message: 'Expense updated successfully' });
      }
    } catch (err) {
      console.error('Failed to update an expense:', err);
      res.status(500).json({ error: 'Failed to update an expense' });
    }
  }
  
  async function deleteExpense(req, res) {
    const id = parseInt(req.params.id);
    const query = 'DELETE FROM expenses WHERE id = $1';
    const values = [id];
  
    try {
      const result = await pool.query(query, values);
      if (result.rowCount === 0) {
        res.status(404).json({ error: 'Expense not found' });
      } else {
        res.json({ message: 'Expense deleted successfully' });
      }
    } catch (err) {
      console.error('Failed to delete an expense:', err);
      res.status(500).json({ error: 'Failed to delete an expense' });
    }
  }
  
  module.exports = {
    getExpenses,
    createExpense,
    deleteExpense,
    updateExpense
  } 

错误原因

核心问题是model层函数设计与路由层调用不匹配:

  • model里的getExpenses、createExpense等函数定义时接收req、res参数,试图直接在model里处理响应
  • 但路由层调用这些函数时,比如expense_model.getExpenses()并没有传递req、res,导致函数内部的res是undefined,调用res.json()就会触发Cannot read properties of undefined (reading 'json')错误
  • 另外CORS配置里的Access-Control-Allow-Origin设为http://localhost:8000,如果前端运行在其他端口(比如3000),会导致跨域错误,引发Axios报错

解决方法

1. 重构model层函数,让它们只处理数据库逻辑并返回数据

修改expense_model.js,去掉函数里的req、res参数,改为返回数据或抛出错误:

const Pool = require('pg').Pool
const pool = new Pool({
    user: 'my_user',
    host: 'localhost',
    database: 'my_database',
    password: 'root',
    port: 5432,
  });

async function getExpenses() {
  try {
    const query = 'SELECT * FROM expenses';
    const result = await pool.query(query);
    return result.rows;
  } catch (err) {
    console.error('Failed to retrieve expenses:', err);
    throw new Error('Failed to retrieve expenses');
  }
}

async function createExpense(expenseData) {
  const { expense, amount, description, tag } = expenseData;
  const query = 'INSERT INTO expenses (expense, amount, description, tag) VALUES ($1, $2, $3, $4) RETURNING *';
  const values = [expense, amount, description, tag];

  try {
    const result = await pool.query(query, values);
    return result.rows[0];
  } catch (err) {
    console.error('Failed to create an expense:', err);
    throw new Error('Failed to create an expense');
  }
}

async function updateExpense(id, expenseData) {
  const { expense, amount, description, tag } = expenseData;
  const query = 'UPDATE expenses SET expense = $1, amount = $2, description = $3, tag = $4 WHERE id = $5';
  const values = [expense, amount, description, tag, id];

  try {
    const result = await pool.query(query, values);
    if (result.rowCount === 0) {
      throw new Error('Expense not found');
    }
    return { message: 'Expense updated successfully' };
  } catch (err) {
    console.error('Failed to update an expense:', err);
    throw err;
  }
}

async function deleteExpense(id) {
  const query = 'DELETE FROM expenses WHERE id = $1';
  const values = [id];

  try {
    const result = await pool.query(query, values);
    if (result.rowCount === 0) {
      throw new Error('Expense not found');
    }
    return { message: 'Expense deleted successfully' };
  } catch (err) {
    console.error('Failed to delete an expense:', err);
    throw err;
  }
}

module.exports = {
  getExpenses,
  createExpense,
  deleteExpense,
  updateExpense
} 

2. 修正路由层的调用逻辑

修改index.js,正确传递参数给model函数,并在路由层处理响应:

const express = require('express')

const app = express()

const port = 8000
const expense_model = require('./expense_model')

app.use(express.json());
app.use(function (req, res, next) {
    // 如果前端运行在其他端口,替换成对应地址,比如http://localhost:3000
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
    res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Access-Control-Allow-Headers');
    next();
  });

app.get('/', async (req, res) => {
  try {
    const expenses = await expense_model.getExpenses();
    res.status(200).json(expenses);
  } catch (error) {
    console.error('Failed to retrieve expenses:', error);
    res.status(500).json({ error: error.message });
  }
});

app.post('/expenses', async (req, res) => {
  try {
    const newExpense = await expense_model.createExpense(req.body);
    res.status(201).json(newExpense);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
})

app.delete('/expenses/:id', async (req, res) => {
  try {
    const result = await expense_model.deleteExpense(parseInt(req.params.id));
    res.status(200).json(result);
  } catch (error) {
    if (error.message === 'Expense not found') {
      res.status(404).json({ error: error.message });
    } else {
      res.status(500).json({ error: error.message });
    }
  }
})

// 补充update路由(之前代码里没用到,但model里有,可选添加)
app.put('/expenses/:id', async (req, res) => {
  try {
    const result = await expense_model.updateExpense(parseInt(req.params.id), req.body);
    res.status(200).json(result);
  } catch (error) {
    if (error.message === 'Expense not found') {
      res.status(404).json({ error: error.message });
    } else {
      res.status(500).json({ error: error.message });
    }
  }
})

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

3. 验证数据库连接(可选)

如果担心数据库连接问题,可以在expense_model.js开头加一段测试代码,确认能正常连接:

// 测试数据库连接
pool.connect((err, client, release) => {
  if (err) {
    return console.error('Error acquiring client', err.stack)
  }
  client.query('SELECT NOW()', (err, result) => {
    release()
    if (err) {
      return console.error('Error executing query', err.stack)
    }
    console.log('数据库连接正常,当前时间:', result.rows[0])
  })
})

额外提示

  • 确保PostgreSQL服务正在运行,且my_database数据库、expenses表已正确创建
  • 前端Axios请求的地址要和后端端口一致,比如后端跑在8000,前端请求地址应为http://localhost:8000/或http://localhost:8000/expenses

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 16:07:03