- Published on
Express 项目的中间件汇总
- Authors
- Name
- Shelton Ma
1. 中间件概述
在 Express 中,中间件是处理请求和响应流程中的核心部分.根据执行时机,可以将中间件分为前中间件(前置中间件)和后中间件(后置中间件).
1. 前置中间件(Pre Middleware)
前置中间件在请求处理开始时执行,通常用于:
参数验证
权限验证
日志记录
请求体解析
设置响应头
静态资源服务
速率限制(防止 API 滥用,限制请求速率)
import rateLimit from 'express-rate-limit'; export const rateLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15分钟窗口 max: 100, // 每个IP最多100个请求 standardHeaders: true, // 返回 `RateLimit-*` 头信息 legacyHeaders: false, // 禁用 `X-RateLimit-*` 头信息 message: { success: false, error: 'Too many requests, please try again later.' }, handler: (req, res) => { res.status(429).json({ success: false, error: 'Too many requests, please try again later.' }); } });
API 请求追踪(记录请求耗时、状态码等,便于追踪性能瓶颈)
import { Request, Response, NextFunction } from 'express'; export function trackPerformance(req: Request, res: Response, next: NextFunction) { const start = process.hrtime(); // 高精度计时器 res.on('finish', () => { const [seconds, nanoseconds] = process.hrtime(start); const durationInMs = (seconds * 1000 + nanoseconds / 1e6).toFixed(2); logger.info({ method: req.method, path: req.originalUrl, statusCode: res.statusCode, duration: `${durationInMs}ms` }); }); next(); }
比如:
import express from 'express'; import pinoHttp from 'pino-http'; import cors from 'cors'; import helmet from 'helmet'; const app = express(); // 前中间件 app.use(rateLimiter); // 防止恶意请求 app.use(trackPerformance); // 性能监控 app.use(express.json()); // 解析 JSON 请求体 app.use(express.urlencoded({ extended: true })); app.use(pinoHttp()); app.use(helmet()); app.use(cookieParser()); app.use(compression()); // 自定义cors // app.use(cors()); app.use(cors({ origin: 'https://example.com', // 仅允许指定来源 methods: ['GET', 'POST'], // 允许的请求方法 allowedHeaders: ['Content-Type', 'Authorization'], // 允许的请求头 credentials: true, // 允许携带 cookies optionsSuccessStatus: 200 // 一些旧版浏览器使用 204 状态时可能会有问题 })); // 自定义验证中间件 参数验证、权限校验、白名单检查 app.use(checkAuth); app.use((req, res, next) => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`); next(); // 继续传递请求 }); // 路由 app.get('/api/data', (req, res) => { res.json({ message: 'Hello World' }); }); // 错误处理中间件 app.use((err, req, res, next) => { console.error('Error:', err); res.status(500).json({ error: 'Internal Server Error' }); }); app.listen(3000, () => console.log('Server running on port 3000'));
2. 后置中间件(Post Middleware)
后置中间件在请求处理完成后执行,主要用于:
- 统一格式化响应数据
- 日志记录
- 错误处理
常见后置中间件示例
中间件 作用 示例代码 统一响应格式化 格式化成功响应,返回统一结构 app.use(responseFormatter); 错误处理器 (err 参数) 捕获并处理路由或中间件中的异常 app.use(errorHandler); 日志记录 记录响应结果、错误信息等 app.use(logErrorHandler); demo
// 统一响应格式中间件 function responseFormatter(req, res, next) { const originalJson = res.json; res.json = function (data) { originalJson.call(this, { success: true, data, timestamp: new Date().toISOString(), }); }; next(); } export function logErrorHandler(err: Error, req: Request, res: Response, next: NextFunction) { logger.error({ message: err.message, stack: err.stack, method: req.method, path: req.originalUrl }); // 继续交由 `errorHandler` 处理响应 next(err); } function errorHandler(err, req, res, next) { console.error(err); res.status(500).json({ success: false, error: err.message, }); } app.use(responseFormatter); app.use(logErrorHandler); app.use(errorHandler);
3. 中间件执行顺序
在 Express 中,中间件的执行顺序遵循以下规则:
- app.use() 定义的中间件按声明顺序执行.
- 匹配的路由处理完毕后,才会执行后续的后中间件(如统一格式化、错误处理).
- next() 控制流程,如果未调用 next(),后续中间件将不会执行.
4. 最佳实践
尽量将
参数校验、权限验证
放在前中间件,避免不必要的业务逻辑执行.使用
res.locals
在前中间件和后中间件之间共享数据,减少重复查询或计算.将
错误处理逻辑
作为单独的后中间件,确保所有异常都能被捕获.项目结构:
/project ├── /middlewares │ ├── authMiddleware.ts │ ├── loggerMiddleware.ts │ ├── errorHandler.ts │ └── responseFormatter.ts ├── /routes │ ├── userRoutes.ts │ ├── orderRoutes.ts │ └── productRoutes.ts ├── app.ts └── server.ts