中间件
中间件是 Express.js 的核心概念,它是一个函数,可以访问请求对象、响应对象和下一个中间件函数。
中间件概念
const middleware = (req, res, next) => {
// 请求处理逻辑
next(); // 调用下一个中间件
};
中间件类型
应用级中间件
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('请求时间:', new Date().toISOString());
next();
});
app.use('/api', (req, res, next) => {
console.log('API 请求');
next();
});
路由级中间件
app.get('/users/:id',
(req, res, next) => {
if (req.params.id === '0') {
next('route');
} else {
next();
}
},
(req, res) => {
res.send('常规用户');
}
);
app.get('/users/:id', (req, res) => {
res.send('特殊用户');
});
错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: '服务器错误' });
});
内置中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
第三方中间件
npm install morgan helmet cors
const morgan = require('morgan');
const helmet = require('helmet');
const cors = require('cors');
app.use(morgan('dev'));
app.use(helmet());
app.use(cors());
常用中间件
日志中间件
const 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);
请求体解析
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
静态文件服务
app.use('/static', express.static('public'));
Cookie 解析
npm install cookie-parser
const cookieParser = require('cookie-parser');
app.use(cookieParser());
app.get('/', (req, res) => {
console.log('Cookies:', req.cookies);
});
Session 管理
npm install express-session
const session = require('express-session');
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: false,
cookie: { secure: false }
}));
自定义中间件
认证中间件
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: '需要登录' });
}
try {
const decoded = verifyToken(token);
req.user = decoded;
next();
} catch (err) {
res.status(401).json({ error: 'Token 无效' });
}
};
app.use('/api/protected', authMiddleware);
权限中间件
const checkRole = (...roles) => {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: '权限不足' });
}
next();
};
};
app.delete('/users/:id', authMiddleware, checkRole('admin'), (req, res) => {
res.json({ message: '删除成功' });
});
限流中间件
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: { error: '请求过于频繁' }
});
app.use('/api', limiter);
中间件执行顺序
app.use((req, res, next) => {
console.log('1. 全局中间件');
next();
});
app.use('/api', (req, res, next) => {
console.log('2. API 中间件');
next();
});
app.get('/api/users', (req, res, next) => {
console.log('3. 路由中间件');
next();
}, (req, res) => {
console.log('4. 路由处理');
res.json({ users: [] });
});
中间件最佳实践
- 按顺序加载:错误处理中间件放在最后
- 异步错误处理:使用 express-async-errors 或包装函数
- 模块化:将中间件分离到独立文件
- 性能考虑:避免不必要的中间件