部署在Heroku的Node.js REST API崩溃报错H10,该如何排查解决?
问题根因
从日志的错误码PROTOCOL_CONNECTION_LOST可以明确,崩溃的核心原因是你使用的单例MySQL长连接被服务端主动断开,且代码中没有对应的错误捕获和重连逻辑,未处理的错误直接抛出导致Node.js进程退出,触发Heroku H10报错。
具体触发场景:MySQL服务端默认会自动关闭闲置超过wait_timeout(通常是8小时)的连接,你初始化时仅连接一次,闲置后连接被断开,后续操作就会抛出未捕获错误。另外你在SQL查询回调中直接throw error,没有错误处理逻辑,也会直接导致进程崩溃。
修复方案
- 替换单例连接为MySQL连接池
连接池会自动管理连接的创建、复用、闲置释放,出现连接断开时也会自动尝试重连,稳定性远高于单例长连接。 - 增加错误捕获逻辑
所有数据库操作的错误都要做统一处理,不要直接抛出,避免进程意外退出。 - 给数据库实例增加全局错误监听
兜底捕获连接层面的错误,避免未捕获错误导致进程崩溃。
完整修改后的代码示例
var express = require('express'); var app = express(); var bodyParser = require('body-parser'); var mysql = require('mysql'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended:true })); app.get('/',function(req , res){ return res.send({error: true,message: 'hello'}) }); // 替换为连接池配置 var dbPool = mysql.createPool({ host: '你的数据库地址', user: '你的数据库用户名', password: '你的数据库密码', database: '你的数据库名', connectionLimit: 10, // 连接池最大连接数,按需调整 acquireTimeout: 30000, timeout: 60000 }); // 兜底监听连接池错误,避免未捕获异常崩溃 dbPool.on('error', function(err) { console.error('数据库连接池错误:', err.code, err.message); }); app.get('/employees',function(req,res){ // 从连接池获取连接执行查询 dbPool.query('SELECT * FROM employeedb',function(error, results, fields){ if (error) { // 不要直接throw,返回错误响应 console.error('查询失败:', error); return res.status(500).send({ error: true, message: '数据库查询失败' }); } return res.send({ error: false, data: results, message: 'users list' }); }); }); app.listen(process.env.PORT, '0.0.0.0',function(){ console.log('App running'); }); module.exports = app;
额外注意事项
- 如果你的MySQL服务部署在第三方平台,需要确认平台的IP白名单规则是否允许Heroku的出口IP访问你的数据库
- package.json配置无需修改,现有依赖已经满足需求
- 部署后如果仍有报错,可以查看Heroku应用的实时日志,定位具体错误信息
内容的提问来源于stack exchange,提问作者Blaq
相关产品推荐
相关产品推荐

