Node.js中间件
介绍
中间件是Node.js应用中的一个核心概念,特别是在Express.js等Web框架中。中间件是一个函数,它可以访问请求对象(req)、响应对象(res)和应用的请求-响应循环中的下一个中间件函数(next)。中间件可以执行各种任务,如日志记录、身份验证、错误处理等。
原理
中间件工作原理
中间件的工作流程:
- 当请求到达服务器时,会依次经过所有注册的中间件
- 每个中间件可以处理请求、修改请求和响应对象、结束请求-响应循环,或调用下一个中间件
- 如果中间件调用next(),则请求会传递给下一个中间件
- 如果中间件没有调用next()且没有结束响应,则请求会被挂起
中间件类型
- 应用级中间件:绑定到app对象的中间件
- 路由级中间件:绑定到express.Router()对象的中间件
- 错误处理中间件:带有四个参数(err, req, res, next)的中间件
- 内置中间件:Express提供的中间件(如express.json())
- 第三方中间件:由社区提供的中间件(如morgan、cors)
图示
请求 -> 中间件1 -> 中间件2 -> ... -> 路由处理函数 -> 响应
| |
v v
日志记录 身份验证
实例
自定义中间件
// logger.js
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next(); // 调用下一个中间件
};
module.exports = logger;
使用中间件
// app.js
const express = require('express');
const logger = require('./logger');
const app = express();
// 应用级中间件
app.use(logger);
app.use(express.json()); // 内置中间件
// 路由级中间件
const userRouter = express.Router();
userRouter.use((req, res, next) => {
console.log('User router middleware');
next();
});
userRouter.get('/', (req, res) => {
res.json({ message: 'User route' });
});
app.use('/api/users', userRouter);
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
// 启动服务器
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
第三方中间件示例
- 安装依赖
npm install morgan cors
- 使用第三方中间件
// app.js
const express = require('express');
const morgan = require('morgan');
const cors = require('cors');
const app = express();
// 使用morgan记录请求日志
app.use(morgan('dev'));
// 使用cors启用跨域资源共享
app.use(cors());
// 路由
app.get('/', (req, res) => {
res.send('Hello World!');
});
// 启动服务器
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
专业解决方案
常用第三方中间件
- morgan:HTTP请求日志中间件
- cors:跨域资源共享中间件
- helmet:安全中间件,设置各种HTTP头部
- express-validator:输入验证中间件
- compression:响应压缩中间件
- multer:文件上传中间件
- passport:身份验证中间件
中间件最佳实践
- 保持中间件简洁,单一职责
- 按照正确的顺序注册中间件
- 错误处理中间件应该放在所有路由后面
- 对于复杂应用,将中间件组织到不同文件中
- 避免在中间件中进行耗时操作,影响性能
- 使用next(err)传递错误给错误处理中间件
性能优化
- 只在需要的路由中使用特定中间件
- 避免不必要的中间件调用
- 缓存频繁使用的中间件结果
- 对于大型应用,考虑使用中间件组合和条件中间件