PostgreSQL+Node.js分页查询报错:$1与$2附近存在语法问题
问题原因
参数化查询的占位符($1、$2)不能用来指定排序字段(ORDER BY后的列名)和排序方向——数据库会把这些参数解析成字符串字面量,最终生成的SQL会变成:
SELECT * FROM users ORDER BY 'user_id' 'DESC' LIMIT ...
这种写法完全不符合SQL语法,自然会触发报错。
解决方法
排序字段和方向需要动态拼接到SQL中,但必须先做合法性校验(防止SQL注入);Limit和Offset可以继续用参数化查询,因为它们是数值类型,不存在注入风险。
修改后的完整代码
const getPagination = (page, size) => { const limit = size ? +size : 4; const offset = page ? page * limit : 0; return { limit, offset }; }; const getUsers = async (req, res) => { // 定义允许排序的字段列表,锁定合法列,防止SQL注入 const allowedOrderFields = ['user_id', 'username', 'email']; // 按你的users表实际字段调整 let orderby = req.query.orderby; // 校验排序字段,不合法则用默认值 if (!allowedOrderFields.includes(orderby)) { orderby = 'user_id'; } let orderDir = req.query.orderDir?.toUpperCase(); // 校验排序方向,只能是ASC或DESC if (!['ASC', 'DESC'].includes(orderDir)) { orderDir = 'DESC'; } const { page, size } = req.query; const { limit, offset } = getPagination(page, size); // 动态拼接合法的排序规则,Limit和Offset保留参数化 const query = `SELECT * FROM users ORDER BY ${orderby} ${orderDir} LIMIT $1 OFFSET $2`; try { const data = await db.query(query, [limit, offset]); console.log(data); res.json(data.rows); } catch (err) { res.status(500).send({ message: err.message || '查询用户时发生错误' }); } };
关键细节
- 合法性校验是核心:必须限制排序字段只能是预设的列名,彻底避免攻击者传入恶意字符串触发SQL注入。
- 排序方向统一大写:强制转成大写格式,避免传入小写的
asc/desc导致语法问题。 - 统一async/await写法:原代码混用
await和.then(),改成try/catch更符合异步代码的规范,可读性更强。
内容的提问来源于stack exchange,提问作者Rajiv Ranjan
相关产品推荐
相关产品推荐

