Node.js 错误处理最佳实践
错误类型
| 类型 | 说明 | 处理方式 |
|---|---|---|
| 同步错误 | throw 抛出 | try/catch |
| 异步回调错误 | (err, result) 首个参数 | 回调内判断 if (err) |
| Promise 错误 | reject | .catch() / try/catch + await |
| EventEmitter 错误 | error 事件 | 必须监听 on('error'),否则崩溃 |
| 未捕获异常 | 未处理的错误 | process.on('uncaughtException') |
同步错误
js
function parseJSON(str) {
try {
return JSON.parse(str)
} catch (err) {
console.error('JSON 解析失败:', err.message)
return null // 返回安全默认值
}
}回调错误
js
fs.readFile('./config.json', (err, data) => {
if (err) {
console.error('读取失败:', err.message)
return // 早返回
}
// 正常处理 data
})Promise / async-await
js
// 统一错误处理中间件
async function handler(req, res) {
try {
const data = await fetchData()
res.json(data)
} catch (err) {
res.status(500).json({ error: err.message })
}
}EventEmitter 错误(重要!)
js
// EventEmitter 不监听 error 会让 Node.js 崩溃!
const emitter = new EventEmitter()
emitter.on('error', (err) => console.error('捕获:', err)) // 必须有这行
emitter.emit('error', new Error('test'))
// Stream 同理
readStream.on('error', (err) => console.error('流错误:', err))全局兜底
js
// 未捕获同步异常(最后防线,记录后应退出重启)
process.on('uncaughtException', (err) => {
console.error('未捕获异常:', err)
process.exit(1) // 此时进程状态不确定,应重启
})
// 未处理的 Promise 拒绝(Node 未来版本会改为退出进程)
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理 Promise 拒绝:', reason)
})自定义错误类
js
class AppError extends Error {
constructor(message, statusCode = 500) {
super(message)
this.statusCode = statusCode
this.isOperational = true // 标记为可预料的业务错误
Error.captureStackTrace(this, this.constructor)
}
}
// 使用
throw new AppError('用户不存在', 404)最佳实践速查
| 原则 | 做法 |
|---|---|
| 不吞错误 | 每个 async 函数用 try/catch 或 .catch() |
| 错误分层 | 业务错误 (4xx) vs 系统错误 (5xx) |
| EventEmitter | 必须监听 error 事件 |
| 全局兜底 | uncaughtException + unhandledRejection |
| 生产环境 | 用 PM2 自动重启 + 日志持久化 |
| 异步函数 | await 的 Promise 必须在外层有 catch |