Middleware API(中间件API)是在客户端请求和服务器响应之间处理请求和响应的软件层。它位于应用程序的核心业务逻辑之外,用于处理横切关注点(cross-cutting concerns)。
每个中间件应只做一件事,保持功能专注。
// 不好的实践 - 一个中间件做多件事
app.use((req, res, next) => {
// 认证
if (!req.headers.authorization) {
return res.status(401).send('Unauthorized');
}
// 日志
console.log(`${req.method} ${req.url}`);
next();
});
// 好的实践 - 分离中间件
app.use(authenticationMiddleware);
app.use(loggingMiddleware);
中间件执行顺序很重要,特别是对于依赖关系的中间件。
// 正确的顺序示例
app.use(helmet()); // 安全相关中间件优先
app.use(cors());
app.use(express.json()); // 解析请求体
app.use(authenticationMiddleware); // 认证
app.use(authorizationMiddleware); // 授权
app.use(routes); // 业务路由
app.use(errorHandler); // 错误处理最后
// 错误处理中间件示例
function errorHandler(err, req, res, next) {
console.error(err.stack);
const statusCode = err.statusCode || 500;
const message = statusCode === 500 ? 'Internal Server Error' : err.message;
res.status(statusCode).json({
error: {
message: message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
}
});
}
// 在路由后使用
app.use(errorHandler);
对于需要配置的中间件,使用工厂函数。
// 中间件工厂示例
function createRateLimiter(options = {}) {
const { windowMs = 15 * 60 * 1000, max = 100 } = options;
const requests = new Map();
return (req, res, next) => {
const ip = req.ip;
const currentTime = Date.now();
if (!requests.has(ip)) {
requests.set(ip, { count: 1, startTime: currentTime });
return next();
}
const record = requests.get(ip);
if (currentTime - record.startTime > windowMs) {
requests.set(ip, { count: 1, startTime: currentTime });
return next();
}
if (record.count >= max) {
return res.status(429).send('Too many requests');
}
record.count++;
next();
};
}
// 使用
app.use(createRateLimiter({ max: 50 }));
// 缓存中间件示例
const cache = new Map();
function cachingMiddleware(ttl = 60) {
return (req, res, next) => {
const key = `${req.method}:${req.originalUrl}`;
if (cache.has(key)) {
const { data, expiry } = cache.get(key);
if (Date.now() < expiry) {
return res.json(data);
}
cache.delete(key);
}
// 重写res.json方法临时缓存响应
const originalJson = res.json;
res.json = (body) => {
cache.set(key, {
data: body,
expiry: Date.now() + ttl * 1000
});
originalJson.call(res, body);
};
next();
};
}
// 安全中间件组合示例
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
app.use(helmet()); // 设置安全HTTP头
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100 // 每个IP限制100个请求
}));
// CSRF保护中间件
app.use((req, res, next) => {
if (['POST', 'PUT', 'DELETE'].includes(req.method)) {
const csrfToken = req.headers['x-csrf-token'];
if (!csrfToken || !validateCsrfToken(csrfToken)) {
return res.status(403).send('Invalid CSRF token');
}
}
next();
});
原因:忘记调用next()或提前返回响应但未阻止后续中间件执行。
解决方案:
app.use((req, res, next) => {
if (!isValidRequest(req)) {
return res.status(400).send('Bad Request'); // 注意使用return
}
next(); // 确保有效请求继续执行
});
原因:例如,在解析请求体之前尝试访问req.body。
解决方案: 确保中间件按正确顺序加载:
原因:中间件执行过多同步操作或阻塞操作。
解决方案:
// 异步中间件示例
app.use(async (req, res, next) => {
try {
await someAsyncOperation();
next();
} catch (err) {
next(err);
}
});
通过遵循这些最佳实践,您可以构建高效、可维护且安全的Middleware API架构。
没有搜到相关的沙龙