🔥第15节:日志记录与错误处理
🌟 引言
大家好,我是老曹。上一节课我们学习了用户认证与 JWT 的实现方法,掌握了如何保护 API 安全。今天我们将进入后端开发的重要领域——日志记录与错误处理。本节课将介绍如何使用 winston 日志库记录应用运行状态、捕获全局异常以及设计统一的错误响应结构。通过本节课的学习,你将能够轻松地在应用中实现健壮的日志和错误管理机制。
📚 课程目标
- 掌握日志记录的基本概念和重要性。
- 学习如何使用
winston记录日志。 - 理解全局异常捕获的实现方法。
- 设计统一的错误响应结构。
- 通过 10 道高频面试题巩固知识点。
🎯 教学内容
🔹 1. 什么是日志记录?
🌟 日志记录是记录应用程序运行状态的过程,包括调试信息、警告和错误等。它是排查问题和优化性能的重要工具。
(1) 核心作用
- 问题排查:记录运行时的错误和异常。
- 性能监控:分析请求耗时和资源使用情况。
- 审计跟踪:记录用户操作行为。
🔹 2. 使用 winston 记录日志
📦 winston 是一个强大的 Node.js 日志库,支持多种传输方式(如文件、控制台)和日志级别。
(1) 安装命令
npm install winston
(2) 示例
const winston = require('winston');
// 创建日志器
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(), // 输出到控制台
new winston.transports.File({ filename: 'app.log' }) // 输出到文件
]
});
// 记录日志
logger.info('This is an info message');
logger.warn('This is a warning message');
logger.error('This is an error message');
解释:
level定义日志级别(如info、warn、error)。transports指定日志输出方式。
🔹 3. 全局异常捕获
📦 在 Node.js 中,未捕获的异常可能导致程序崩溃。我们需要实现全局异常捕获机制。
(1) 示例
process.on('uncaughtException', (err) => {
console.error('Uncaught Exception:', err.message);
logger.error('Uncaught Exception:', { error: err });
process.exit(1); // 退出进程
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
logger.error('Unhandled Rejection:', { error: reason });
});
解释:
uncaughtException捕获同步代码中的未捕获异常。unhandledRejection捕获 Promise 中的未处理拒绝。
🔹 4. 统一的错误响应结构
📦 设计一致的错误响应结构,提升 API 的可维护性和用户体验。
(1) 示例
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true; // 区分操作性错误和编程错误
}
}
// 错误处理中间件
const errorHandler = (err, req, res, next) => {
const statusCode = err.statusCode || 500;
const message = err.message || 'Internal Server Error';
res.status(statusCode).json({
status: err.status,
message
});
};
module.exports = { AppError, errorHandler };
解释:
AppError自定义错误类,包含状态码和错误类型。errorHandler中间件统一处理错误并返回 JSON 响应。
🔹 5. 实现完整的日志与错误管理
📦 将日志记录和错误处理集成到 Express 应用中。
(1) 示例
const express = require('express');
const { logger } = require('./logger'); // 引入日志器
const { AppError, errorHandler } = require('./errors'); // 引入错误处理模块
const app = express();
// 测试路由
app.get('/test', (req, res, next) => {
try {
throw new AppError('Something went wrong!', 500);
} catch (err) {
next(err); // 将错误传递给错误处理中间件
}
});
// 错误处理中间件
app.use(errorHandler);
// 启动服务器
app.listen(3000, () => {
logger.info('Server is running on http://localhost:3000');
});
解释:
next(err)将错误传递给errorHandler中间件。logger.info记录服务器启动日志。
🔹 6. 10 大高频面试题
🎯 以下是关于日志记录与错误处理的常见面试问题及答案:
-
问:什么是日志记录?
- 答:记录应用程序运行状态的过程,用于问题排查和性能监控。
-
问:winston 的作用是什么?
- 答:winston 是一个日志库,支持多种传输方式和日志级别。
-
问:如何捕获全局异常?
- 答:使用
process.on('uncaughtException')和process.on('unhandledRejection')。
- 答:使用
-
问:什么是统一的错误响应结构?
- 答:设计一致的 JSON 格式,包含状态码、错误类型和消息。
-
问:如何区分操作性错误和编程错误?
- 答:通过自定义错误类(如
AppError)标记操作性错误。
- 答:通过自定义错误类(如
-
问:如何记录日志到文件?
- 答:使用
winston.transports.File。
- 答:使用
-
问:如何处理未捕获的 Promise 拒绝?
- 答:监听
unhandledRejection事件。
- 答:监听
-
问:日志级别有哪些?
- 答:常见的有
info、warn、error、debug。
- 答:常见的有
-
问:为什么需要统一的错误响应?
- 答:提升 API 的可维护性和用户体验。
-
问:如何退出进程以防止未捕获异常导致的崩溃?
- 答:调用
process.exit(1)。
- 答:调用
📝 练习任务
- 使用
winston实现日志记录功能,并将日志输出到文件。 - 设计一个自定义错误类,并在 Express 应用中实现统一的错误响应。
🔁 拓展建议
✨ 如果你想进一步提升,可以尝试以下拓展任务:
- 学习如何将日志存储到远程服务(如 Elasticsearch)。
- 研究如何结合 APM 工具(如 New Relic)进行性能监控。
- 学习如何实现更细粒度的日志过滤和格式化。
🏆 总结
🎉 本节课我们学习了日志记录与错误处理的基本方法,掌握了如何使用 winston 记录日志、捕获全局异常以及设计统一的错误响应结构。通过实战案例和高频面试题,相信你已经能够在应用中实现健壮的日志和错误管理机制!下一节课我们将学习文件上传与下载的实现方法。期待与大家再次见面!
希望老曹这节课对你有所帮助,我们下节课见! 😊
796

被折叠的 条评论
为什么被折叠?



