Node.js在Linux上的错误处理策略
全局错误处理器是防止Node.js进程因未处理错误崩溃的最后防线。需监听两个核心事件:
uncaughtException
:捕获未被try-catch
或.catch()
处理的同步/异步异常(如代码逻辑错误、未捕获的Promise拒绝)。处理时需记录详细错误日志(包括堆栈信息),并根据业务需求决定是否重启进程(避免无限崩溃)。unhandledRejection
:捕获未被处理的Promise拒绝(如Promise.reject()
未接.catch()
)。建议在此处记录拒绝原因(reason
)和关联的Promise对象,帮助定位异步代码中的问题。process.on('uncaughtException', (error) => {
console.error('未捕获异常:', error.stack);
// 记录日志后,可选择优雅退出或重启(需配合进程管理工具)
process.exit(1); // 生产环境建议用pm2等工具重启
});
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理Promise拒绝:', reason, 'Promise:', promise);
});
模块级错误处理需结合同步与异步场景:
try-catch
包裹可能抛出异常的代码(如文件读取、数据库查询)。try {
const data = fs.readFileSync('/path/to/file.txt', 'utf8');
} catch (error) {
console.error('文件读取失败:', error.message);
}
fs.readFile('/path/to/file.txt', 'utf8', (err, data) => {
if (err) {
console.error('文件读取失败:', err.message);
return;
}
console.log(data);
});
.catch()
捕获拒绝,或async/await
配合try-catch
(更易读)。async function fetchData() {
try {
const response = await axios.get('https://api.example.com/data');
console.log(response.data);
} catch (error) {
console.error('API请求失败:', error.response?.status || error.message);
}
}
日志是错误排查的核心依据,需遵循结构化、分级、轮转原则:
const winston = require('winston');
const logger = winston.createLogger({
level: 'error', // 生产环境仅记录error及以上级别
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json() // 结构化日志便于ELK分析
),
transports: [
new winston.transports.File({ filename: 'logs/error.log' }), // 错误日志单独存储
new winston.transports.Console({ format: winston.format.simple() }) // 控制台输出简化格式
]
});
winston-daily-rotate-file
插件(Winston扩展)或Linux系统工具logrotate
实现。logrotate
配置,/etc/logrotate.d/nodejs
):/path/to/app.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate
}
监控是提前发现错误的关键,需结合进程状态与错误指标:
--restart
参数)。pm2 start app.js --name "my-app" --restart-delay=3000 # 崩溃后3秒重启
const Sentry = require('@sentry/node');
Sentry.init({ dsn: 'YOUR_DSN_HERE' }); // 配置Sentry项目地址
通过设计降低错误对系统的影响:
cluster
模块启动多个工作进程(共享端口),提高可用性。const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
const numCPUs = os.cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork(); // 启动子进程
}
cluster.on('exit', (worker) => {
console.log(`Worker ${worker.process.pid} died, restarting...`);
cluster.fork(); // 子进程崩溃后重启
});
} else {
require('./app'); // 子进程执行应用逻辑
}
从源头减少错误:
npm outdated
),使用npm audit
修复安全漏洞,避免依赖冲突。资源泄漏(如文件描述符、数据库连接)会导致进程崩溃,需正确释放:
fs.close()
关闭打开的文件,或用stream.destroy()
销毁流。pg-pool
for PostgreSQL),并在应用退出时关闭连接。const { Pool } = require('pg');
const pool = new Pool({ connectionString: 'YOUR_DB_URL' });
// 使用连接
pool.query('SELECT * FROM users', (err, res) => {
if (err) throw err;
console.log(res.rows);
pool.end(); // 关闭连接池
});
clearTimeout
/clearInterval
)和事件监听器(removeListener
),避免内存泄漏。