答案:未处理的Async/Await拒绝会导致Node.js进程崩溃,尤其在Node.js v15+版本中,未捕获的Promise拒绝会直接触发进程退出。实习生小王的代码因未包裹try-catch,当数据库查询返回无效数据(如coupon为undefined)时,访问coupon.id会抛出异常,导致进程崩溃。
1. 问题根源分析2. 解决方案青铜方案:手动添加try-catchrouter.post('/use-coupon', async (req, res) => { try { const { code } = req.body; const coupon = await db.query('SELECT * FROM coupons WHERE code = ?', [code]); if (!coupon) throw new Error('优惠券不存在'); await db.query('UPDATE coupons SET status = "used" WHERE id = ?', [coupon.id]); res.json({ success: true }); } catch (err) { console.error(err); res.status(500).json({ error: '服务异常' }); }});黄金方案:Express全局错误中间件// 全局错误处理中间件(需放在路由之后)app.use((err, req, res, next) => { Sentry.captureException(err); // 上报异常 metrics.increment('server.error'); // 监控计数 res.status(500).send('服务端错误');});王者方案:进程级安全网// 捕获未处理的Promise拒绝process.on('unhandledRejection', (reason, promise) => { Sentry.withScope(scope => { scope.setTag('crash_type', 'unhandled_rejection'); Sentry.captureException(reason); }); logger.fatal('未捕获拒绝,但保持进程存活:', reason); // 可选:阻止进程退出(根据业务需求)});PM2托底配置(ecosystem.config.js)module.exports = { apps: [{ name: 'server', script: 'app.js', max_restarts: 5, // 最大重启次数 min_uptime: '60s' // 最小存活时间 }]};3. 预防措施团队规范监控与测试4. 延伸思考- 开发效率与异常处理的平衡:团队可通过代码模板、ESLint规则(如eslint-plugin-promise)强制要求错误处理,同时利用AOP(面向切面编程)封装通用错误处理逻辑。
- 防御性编码秘籍:
使用TypeScript或JSDoc明确函数可能抛出的异常类型。
对第三方库调用添加超时和重试机制(如p-retry)。
关键操作前添加参数校验(如Joi或class-validator)。
总结Async/Await的异常处理是线上服务稳定性的基石。通过显式捕获、全局中间件和进程级兜底,结合监控与测试,可避免因未处理拒绝导致的服务崩溃。正如小王在复盘会上所言:“异常处理不是可选项,而是生存法则。”