Node.js未捕获异常处理:Express REST API服务器的最佳实践问询
在Express REST API中处理未捕获异常的首选方式
作为常年维护Express REST API的开发者,我会推荐分层处理策略——从全局进程层面兜底,到请求生命周期内的精细化捕获,同时配合进程管理工具,确保服务器稳定且错误可追溯。
1. 全局层面:捕获uncaughtException并优雅重启
Node.js的process对象会在同步代码抛出未捕获异常时触发uncaughtException事件。不过要注意:官方明确不建议捕获后继续运行进程,因为此时进程状态可能已不稳定,容易出现数据损坏或未知行为。
正确的做法是:捕获异常后记录日志、清理资源,然后退出进程,让进程管理器(如PM2)自动重启。
const express = require('express'); const app = express(); const server = app.listen(3000); // 捕获全局未捕获的同步异常 process.on('uncaughtException', (err) => { console.error('[FATAL] Uncaught Exception:', err.stack); // 先清理资源:关闭数据库连接、HTTP服务器等 server.close(() => { console.log('Server closed gracefully'); process.exit(1); // 退出后让PM2重启 }); // 超时强制退出,避免资源清理卡住 setTimeout(() => { console.error('Force exiting after timeout'); process.exit(1); }, 10000); });
2. 请求生命周期内:用Express错误处理中间件捕获异常
Express提供了错误处理中间件机制,能捕获路由中抛出的同步异常,以及通过next(err)传递的异步异常。
第一步:添加全局错误处理中间件
必须放在所有路由和其他中间件之后:
// 所有路由定义... // 错误处理中间件(四个参数必须齐全) app.use((err, req, res, next) => { console.error('[REQUEST ERROR]', { path: req.path, method: req.method, error: err.stack }); // 生产环境返回通用错误,开发环境返回详细信息 const response = process.env.NODE_ENV === 'production' ? { error: 'Internal Server Error' } : { error: err.message, stack: err.stack }; res.status(err.statusCode || 500).json(response); });
第二步:捕获异步路由中的异常
对于async/await的路由,需要手动用try/catch捕获异常,然后通过next(err)传递给错误处理中间件。也可以用包装函数简化这个过程:
// 封装一个async路由的错误捕获函数 const asyncHandler = (fn) => (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; // 使用示例 app.get('/api/users', asyncHandler(async (req, res) => { // 这里的异步异常会被自动捕获并传给错误处理中间件 const users = await User.find(); res.json(users); }));
3. 处理未捕获的Promise拒绝(unhandledRejection)
Promise中未被catch的异常不会触发uncaughtException,但会导致进程发出警告,长期运行可能引发内存泄漏。必须监听这个事件:
process.on('unhandledRejection', (reason, promise) => { console.error('[UNHANDLED REJECTION] Promise:', promise, 'Reason:', reason.stack); // 同样优雅关闭并重启 server.close(() => process.exit(1)); });
4. 额外最佳实践
- 强制使用进程管理器:比如PM2,它能在进程退出后自动重启,还提供日志管理、负载均衡等功能,是生产环境的标配。
- 集中化日志:用Winston、Bunyan等日志库把错误信息(包括请求上下文、堆栈)记录到文件或日志服务,方便后续排查问题。
- 避免在全局异常处理中恢复进程:不要尝试在
uncaughtException里修复错误后继续运行,进程状态已不可靠,重启是最安全的选择。
内容的提问来源于stack exchange,提问作者Naveen
相关产品推荐
相关产品推荐

