面试题答案
一键面试1. 日志记录
- 使用专业日志库:在Node.js中,可使用
winston
或pino
等日志库。例如winston
,它支持多种日志级别(如info
、warn
、error
等),能方便地将不同级别的错误记录到文件或控制台。
const winston = require('winston');
const logger = winston.createLogger({
level: 'error',
format: winston.format.json(),
transports: [
new winston.transport.Console(),
new winston.transport.File({ filename: 'error.log' })
]
});
try {
// 异步操作
setTimeout(() => {
throw new Error('异步操作出错');
}, 1000);
} catch (error) {
logger.error({
message: error.message,
stack: error.stack
});
}
- 详细错误信息:记录错误的堆栈跟踪(
stack
),方便定位错误发生的具体位置,同时记录与错误相关的上下文信息,如请求参数、用户ID等,有助于分析问题。
2. 错误监控
- 集成监控工具:利用
Sentry
、New Relic
等监控工具。以Sentry
为例,它能自动捕获应用中的错误,提供详细的错误报告和性能分析。- 安装
@sentry/node
:npm install @sentry/node
- 初始化Sentry:
- 安装
const Sentry = require('@sentry/node');
Sentry.init({
dsn: 'YOUR_DSN_HERE'
});
try {
// 异步操作
setTimeout(() => {
throw new Error('异步操作出错');
}, 1000);
} catch (error) {
Sentry.captureException(error);
}
- 自定义监控指标:除了捕获错误,还可自定义一些指标,如异步任务的执行时间、失败率等,通过
Prometheus
结合Node.js
的prom-client
库实现。
3. 资源释放
- 使用
finally
块:在try - catch - finally
结构中,finally
块无论是否发生错误都会执行,可用于释放资源,如关闭数据库连接、文件描述符等。
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'test'
});
connection.connect();
try {
connection.query('SELECT * FROM users', (error, results) => {
if (error) {
throw error;
}
console.log(results);
});
} catch (error) {
console.error('查询出错:', error);
} finally {
connection.end();
}
- 事件监听和清理:对于一些基于事件的异步操作,如
stream
,监听error
和end
事件,在事件处理函数中进行资源清理。
const fs = require('fs');
const readableStream = fs.createReadStream('test.txt');
readableStream.on('error', (error) => {
console.error('读取文件出错:', error);
// 可能的资源清理操作
});
readableStream.on('end', () => {
// 流结束,可进行相关清理
});
实际案例
假设开发一个基于Node.js的文件上传服务,使用express
框架和multer
中间件处理文件上传。
- 日志记录:使用
winston
记录上传过程中的错误,如文件大小超过限制、文件类型不允许等错误,记录详细的错误信息和请求上下文。 - 错误监控:集成
Sentry
,当出现未处理的错误(如服务器内存不足导致上传失败)时,Sentry能及时捕获并通知开发团队,同时提供错误发生时的环境信息。 - 资源释放:在文件上传过程中,如果发生错误,确保临时文件被删除,避免占用磁盘空间。使用
finally
块关闭与文件操作相关的流,防止资源泄漏。
const express = require('express');
const multer = require('multer');
const winston = require('winston');
const Sentry = require('@sentry/node');
Sentry.init({
dsn: 'YOUR_DSN_HERE'
});
const logger = winston.createLogger({
level: 'error',
format: winston.format.json(),
transports: [
new winston.transport.Console(),
new winston.transport.File({ filename: 'upload - error.log' })
]
});
const app = express();
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('file'), (req, res) => {
try {
// 文件上传成功处理逻辑
res.send('文件上传成功');
} catch (error) {
logger.error({
message: error.message,
stack: error.stack,
request: req.body
});
Sentry.captureException(error);
res.status(500).send('文件上传失败');
} finally {
// 如果有临时文件,进行删除操作
if (req.file) {
const fs = require('fs');
fs.unlinkSync(req.file.path);
}
}
});
const port = 3000;
app.listen(port, () => {
console.log(`服务器运行在端口 ${port}`);
});