You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:42:07