本文讲解如何在 express 应用中安全、可靠地执行 mysql 查询并基于查询结果设置 cookie,避免因异步操作不当导致应用崩溃或响应提前发送的问题。
本文讲解如何在 express 应用中安全、可靠地执行 mysql 查询并基于查询结果设置 cookie,避免因异步操作不当导致应用崩溃或响应提前发送的问题。
在 Node.js 中使用 MySQL 时,一个常见且致命的错误是忽视其异步非阻塞特性:db.query() 是异步操作,若未等待查询完成就调用 res.send() 或 res.cookie(),将导致响应被多次发送(Cannot set headers after they are sent)或读取 undefined 数据(如 results[0] 为空时访问 .vorname 报错),最终引发进程崩溃。
您原始代码存在多个关键问题:
- ❌ SQL 注入风险:直接拼接 data 到 SQL 字符串中(WHERE id ='" + data + "'"),极易遭受攻击;
- ❌ 并发查询无序执行:两个 db.query() 并行发起,但 res.send("Hallo") 在它们回调外立即执行,导致响应提前结束;
- ❌ 未校验查询结果:results[0] 可能为 undefined(如 ID 不存在),直接访问 .vorname 会抛出 TypeError;
- ❌ 连接管理不当:使用 mysql.createConnection() 却未做连接复用/错误重试,且 db.end 写法无效(应为 db.end() 且不应放在模块导出后);
- ❌ 缺少错误处理:所有查询均未捕获 err,一旦数据库异常(如连接断开、语法错误),服务将静默失败或崩溃。
✅ 正确做法是:统一单次查询获取所需字段 + 使用参数化查询防止注入 + 在查询回调内完成所有响应逻辑 + 健壮的错误与空值校验。
使用一条命令部署ProbeChain Rydberg测试网代理节点。自动注册为Agent(NodeType=1),免gas,支持macOS/Linux/Windows。触发词:/r
以下为优化后的完整实现:
const express = require('express');
const mysql = require('mysql');
const router = express.Router();
// ✅ 推荐使用连接池(而非单连接),提升并发稳定性与资源复用
const db = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: 'root',
password: '',
database: 'data',
multipleStatements: false, // 默认 false 更安全,除非明确需要多语句
charset: 'utf8mb4'
});
// /test01:保持原功能,仅补充基础错误处理
router.get('/test01', (req, res) => {
db.query('SELECT * FROM uebersicht', (err, results) => {
if (err) {
console.error('Query failed in /test01:', err);
return res.status(500).send('Database error');
}
res.render('page', { results });
});
});
// /test02:核心修复 —— 单次查询 + 参数化 + 安全响应
router.get('/test02', (req, res) => {
const cookieId = req.cookies.id;
// ? 必须校验输入:ID 不能为空或非数字(根据业务调整)
if (!cookieId || isNaN(Number(cookieId))) {
return res.status(400).send('Invalid or missing cookie ID');
}
// ✅ 参数化查询:? 占位符自动转义,杜绝 SQL 注入
db.query(
'SELECT vorname, nachname FROM uebersicht WHERE id = ?',
[cookieId], // 参数数组,对应 ? 的值
(err, results) => {
if (err) {
console.error('Query failed in /test02:', err);
return res.status(500).send('Database query failed');
}
// ✅ 严格校验查询结果
if (results.length === 0) {
return res.status(404).send('User not found');
}
const { vorname, nachname } = results[0];
// ✅ 在同一回调内设置 Cookie 并发送响应
res.cookie('vorname', vorname, { path: '/' });
res.cookie('nachname', nachname, { path: '/' });
res.send('Hallo');
}
);
});
module.exports = router;关键改进说明:
- 连接池替代单连接:createPool() 自动管理连接生命周期,避免连接耗尽;
- 参数化查询(? 占位符):MySQL 驱动自动处理类型转换与转义,彻底规避 SQL 注入;
- 单一查询代替多次查询:一次查出 vorname 和 nachname,减少数据库往返,提升性能与一致性;
- 前置输入校验 + 结果存在性检查:防止 undefined 访问和无效请求冲击数据库;
- 错误统一处理并返回 HTTP 状态码:使前端可明确区分客户端错误(4xx)与服务端错误(5xx);
- 响应逻辑完全包裹在回调内:确保 res.send() 仅在数据就绪后执行,杜绝“headers already sent”错误。
? 进阶建议:生产环境应进一步升级为 mysql2(支持 Promise API)、配合 async/await 写法提升可读性;Cookie 敏感信息建议加密(如 cookie-parser 配合 signed cookies);长期项目推荐迁移至 TypeORM 或 Prisma 等 ORM 工具以增强类型安全与维护性。

















