Node.js 后端错误处理与日志规范
为什么需要规范的错误处理
刚入门的 Node.js 项目往往用 try-catch 满天飞,每个接口里都套一层,代码臃肿不说,处理方式也不统一——有的返回 500,有的返回自定义错误码,排查问题时简直噩梦。
建立一套全局统一的错误处理机制后,接口层的代码量能降一半以上,而且排查效率明显提高。
自定义错误类
先定义一个继承 Error 的业务错误类,方便区分不同类型的异常:
class AppError extends Error {
constructor(message, statusCode, code) {
super(message)
this.statusCode = statusCode
this.code = code
this.isOperational = true
}
}
// 使用
throw new AppError('用户不存在', 404, 'USER_NOT_FOUND')
全局错误中间件
Express 的错误中间件放在所有路由之后,统一捕获错误:
// 放在 router 注册之后
app.use((err, req, res, next) => {
const statusCode = err.statusCode || 500
const message = err.isOperational ? err.message : '服务器内部错误'
console.error(`[${new Date().toISOString()}] ${err.stack}`)
res.status(statusCode).json({
success: false,
code: err.code || 'INTERNAL_ERROR',
message
})
})
异步错误的处理
Express 4 默认不捕获 promise 中的异常,需要包装一下:
// utils/catchAsync.js
module.exports = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next)
}
// 路由中使用
router.get('/users', catchAsync(async (req, res) => {
const users = await User.findAll()
res.json({ success: true, data: users })
}))
PM2 日志管理
生产环境用 PM2 管理进程,日志自动写入文件。建议配置日志轮转:
// 安装 pm2-logrotate
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 30
小结
- 自定义 AppError 区分业务错误和系统错误
- 全局错误中间件统一处理,保证接口返回格式一致
- 用 catchAsync 包装异步路由,避免手动 try-catch
- 生产环境结合 PM2 logrotate 管理日志文件