配置NodeExpress部署及解决运行数小时后出现500内部错误的问题
问题原因排查
- MySQL单连接超时断开
代码中使用的是单连接模式访问MySQL,未配置断线重连逻辑,MySQL服务端默认的闲置连接超时时间(wait_timeout)通常为8小时,连接闲置超过该时长后服务端会主动断开连接,客户端不知情的情况下继续使用该连接执行SQL就会抛出错误,完全符合你运行数小时后出现500的现象。 - 错误未捕获处理
所有connection.query的回调函数中完全没有处理err参数,SQL执行出错后既没有抛出也没有传给Express的错误处理中间件,最终被全局错误中间件捕获返回500,且生产环境下你配置了错误信息不返回,根本无法直接感知具体报错原因。 - 错误响应格式不匹配
你的错误处理中间件默认返回Jade渲染的HTML错误页面,接口请求出错后不会返回JSON格式数据,和你提到的「不再返回JSON」的现象完全吻合。 - SQL注入风险
直接拼接用户传入的参数到SQL语句中,没有做转义处理,遇到带特殊字符(比如单引号)的搜索内容时会直接导致SQL语法错误,也存在被拖库的安全风险。
解决办法
- 替换单MySQL连接为连接池,自带连接复用、断线重连能力,避免连接超时问题,示例代码:
const mysql = require('mysql2/promise'); const pool = mysql.createPool({ host: '你的数据库地址', user: '数据库用户名', password: '数据库密码', database: '库名', connectionLimit: 10, // 按需配置连接数 waitForConnections: true }); // 后续查询直接使用pool.query即可
- 所有数据库操作必须捕获错误,传递给Express错误处理中间件:
pool.query(sql语句, 参数, (err, rows, fields) => { if (err) return next(err); // 出错透传给错误中间件 res.json({content : rows.slice(pageM,pageM+10),row_count:rows.length}) })
- 改用参数化查询,避免SQL注入和特殊字符报错:
// 示例:把拼接SQL改为参数占位 const sql = `SELECT * FROM documento WHERE descricao_detalhada LIKE ? OR descricao_detalhada LIKE ?` pool.query(sql, [`%${numeric_repr}%`, `%${searchValue}%`], (err, rows) => { // 业务逻辑 })
- 调整错误处理中间件,适配API请求返回JSON格式:
app.use(function(err, req, res, next) { const statusCode = err.status || 500; res.status(statusCode); // API请求返回JSON,其他请求返回错误页 if (req.path.startsWith('/leis') || req.path.startsWith('/documento')) { res.json({ code: statusCode, message: process.env.NODE_ENV === 'development' ? err.message : '服务器内部错误' }) return } res.locals.message = err.message; res.locals.error = process.env.NODE_ENV === 'development' ? err : {}; res.render('error'); });
- 通过
pm2 logs命令查看服务运行日志,可以直接定位具体的报错信息。
Node.js生产环境部署注意事项
- 进程管理:使用PM2时建议配置多进程模式(
pm2 start app.js -i max自动匹配CPU核心数),开启PM2开机自启,配置日志切割避免日志文件占用过大磁盘空间。 - 数据库:必须使用连接池访问数据库,不要硬编码数据库账号密码等敏感信息,通过环境变量加载配置。
- 错误处理:全局监听
uncaughtException和unhandledRejection事件,避免未捕获的异步错误直接导致服务崩溃,所有异步操作必须做错误捕获。 - 性能优化:分页查询不要全表拉取后在代码层切片,改用SQL的
LIMIT语法实现数据库层面分页,数据量较大时能大幅降低内存占用和查询耗时。 - 安全加固:关闭Express默认的
x-powered-by响应头,避免泄露技术栈;所有用户输入必须做合法性校验,杜绝直接拼接SQL的写法。
内容的提问来源于stack exchange,提问作者Icaro Amorim
相关产品推荐
相关产品推荐

