为什么部署在Heroku的Node.js REST API运行几分钟后就崩溃?
问题根因
从Heroku日志可以明确崩溃原因是PROTOCOL_CONNECTION_LOST,即MySQL服务端主动断开了和你应用的连接。你当前使用mysql.createConnection创建的是单例长连接,MySQL服务端默认会关闭闲置超过超时阈值的连接(云厂商提供的MySQL服务超时阈值通常只有几分钟),而你的代码没有连接断开后的自动重连逻辑,遇到连接错误直接抛出未捕获的异常,导致整个Node进程崩溃。
另外你的代码还存在几个会导致崩溃的隐性问题:
/usuarios/:id路由中变量名拼写错误:判断长度时写的是resul.length,实际返回结果变量是result,触发未定义变量异常bcrypt.hash是异步方法,你当前的写法直接将Promise对象存入数据库,会触发数据格式错误- 所有数据库操作的错误回调直接
throw error,单个请求出错就会导致整个进程退出
修复方案
1. 替换单连接为MySQL连接池
连接池会自动管理连接的生命周期,闲置连接断开后会自动重连,同时能更好地控制并发连接数,替换原来的MySQL连接创建代码,同时删除原有的cnx.connect()连接逻辑,连接池会自动处理连接建立:
// 替换原有的MySql单连接配置 const cnx = mysql.createPool({ host: 'any_host', user: 'any_user', password: 'any_password', database: 'any_database', connectionLimit: 10, // 免费层MySQL服务这个配置足够使用 waitForConnections: true, queueLimit: 0 });
2. 修复代码拼写错误
修改/usuarios/:id路由中的变量名:
// 原来的if (resul.length > 0) 修改为 if (result.length > 0) { res.json(result); }else{ res.send('No hay resultados'); }
3. 修复bcrypt异步调用问题
修改/add路由中密码加密的逻辑,使用回调处理异步返回的哈希值:
app.post('/add', (req, res) => { const sql = 'INSERT INTO usuario SET ?'; const saltRounds = 10; // 用回调处理异步加密 bcrypt.hash(req.body.contraseña, saltRounds, (err, contraseñaHash) => { if (err) { console.error(err); return res.status(500).send('密码加密失败'); } const usuarioObj = { cuenta: req.body.cuenta, contraseña: contraseñaHash, nombre: req.body.nombre, apellido: req.body.apellido }; cnx.query(sql, usuarioObj, error => { if (error) { console.error(error); return res.status(500).send('创建用户失败'); } res.send('Usuario creado'); }); }); });
4. 优化错误处理避免进程崩溃
所有数据库操作的错误回调不要直接抛出异常,改为返回错误响应,示例:
// 原来的if (error) throw error; 统一修改为 if (error) { console.error(error); return res.status(500).send('服务器内部错误'); }
修改完成后重新部署到Heroku即可解决崩溃问题。
内容的提问来源于stack exchange,提问作者Jesus Gutierrez
相关产品推荐
相关产品推荐

