一个常用的 Express 中间件是 morgan,它是一个 HTTP 请求日志记录中间件,用于记录每个请求的详细信息,如请求方法、URL、状态码、响应时间等。morgan 是 Express 生态系统中非常流行的日志记录工具,广泛应用于开发和生产环境中。
1. morgan 的功能
- 记录 HTTP 请求的详细信息。
- 支持多种预定义的日志格式(如
combined、common、dev、short、tiny)。 - 支持自定义日志格式。
- 可以将日志输出到控制台、文件或其他流中。
2. 使用 morgan 的示例
2.1 基本用法
const express = require('express');
const morgan = require('morgan');
const app = express();
// 使用默认的 'dev' 格式记录日志
app.use(morgan('dev'));
app.get('/', (req, res) => {
res.send('Hello, World!');
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
- 当访问
http://localhost:3000时,控制台会输出类似以下的日志:
GET / 200 12.123 ms - 13
GET:请求方法。/:请求的 URL。200:响应状态码。12.123 ms:响应时间。13:响应内容的长度。
2.2 使用其他预定义格式
app.use(morgan('combined')); // 使用 'combined' 格式
combined格式会输出更详细的信息,包括远程地址、请求时间、HTTP 版本等。
2.3 将日志写入文件
const fs = require('fs');
const path = require('path');
// 创建一个写入流
const accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' });
// 将日志写入文件
app.use(morgan('combined', { stream: accessLogStream }));
3. morgan 的实现原理
3.1 中间件的基本结构
morgan 是一个标准的 Express 中间件,其核心是一个函数,接收请求对象(req)、响应对象(res)和 next 函数作为参数。它的基本结构如下:
function morgan(format, options) {
return (req, res, next) => {
// 记录日志的逻辑
next();
};
}
3.2 日志格式
morgan 支持预定义格式和自定义格式。预定义格式是通过字符串定义的,例如 dev、combined 等。自定义格式可以通过函数或字符串模板实现。
-
预定义格式:
dev:简洁的开发环境日志。combined:详细的日志,包括远程地址、请求时间等。common:Apache 风格的日志。short:简短的日志。tiny:极简的日志。
-
自定义格式:
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
3.3 日志记录逻辑
morgan 的核心逻辑是在请求完成时(即响应结束时)记录日志。它通过监听响应对象的 finish 事件来实现:
function morgan(format, options) {
return (req, res, next) => {
const start = Date.now();
// 监听响应结束事件
res.on('finish', () => {
const duration = Date.now() - start;
const log = `${req.method} ${req.url} ${res.statusCode} ${duration}ms`;
console.log(log); // 输出日志
});
next();
};
}
3.4 支持输出到流
morgan 支持将日志输出到任意流(如文件流、控制台流等)。通过 options.stream 参数可以指定输出目标:
function morgan(format, options) {
const stream = options.stream || process.stdout;
return (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
const log = `${req.method} ${req.url} ${res.statusCode} ${duration}ms\n`;
stream.write(log); // 将日志写入流
});
next();
};
}
4. 自定义日志中间件的实现
如果你想实现一个简单的日志中间件,可以参考以下代码:
function logger(req, res, next) {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.url} ${res.statusCode} ${duration}ms`);
});
next();
}
app.use(logger);
5. 总结
morgan的功能:记录 HTTP 请求的详细信息,支持多种日志格式和输出目标。- 实现原理:通过监听响应对象的
finish事件,在请求完成时记录日志。 - 自定义日志中间件:可以基于
morgan的原理实现自己的日志中间件。
morgan 是一个非常强大且灵活的日志记录工具,能够帮助开发者更好地监控和调试 Express 应用。