常用中间件库推荐与比较
Express 常用中间件库推荐与比较
Express 作为 Node.js 最流行的 Web 框架之一,其灵活性和可扩展性很大程度上依赖于中间件。选择合适的中间件可以显著提升开发效率和项目质量。以下是一些常用中间件库的详细介绍和对比分析。
请求体解析中间件
body-parser
body-parser
是 Express 中处理 HTTP 请求体的经典中间件,支持 JSON、URL-encoded 和文本格式的解析。
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
// 解析 application/json
app.use(bodyParser.json());
// 解析 application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/api/users', (req, res) => {
console.log(req.body); // 获取解析后的请求体
res.send('User created');
});
express.json() 和 express.urlencoded()
Express 4.16.0 开始内置了这两个中间件,功能与 body-parser
类似,推荐优先使用内置方案。
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
比较:
body-parser
是独立模块,功能更全面(如支持文本解析)- 内置中间件更轻量,适合基本需求
静态文件服务
serve-static
Express 内置的 express.static
中间件基于 serve-static
模块,用于提供静态文件服务。
// 提供 public 目录下的静态文件
app.use(express.static('public'));
// 带虚拟路径前缀
app.use('/static', express.static('public'));
高级配置示例:
app.use('/static', express.static('public', {
index: false, // 禁用目录索引
maxAge: '1d', // 设置缓存头
setHeaders: (res, path) => {
if (path.endsWith('.gz')) {
res.set('Content-Encoding', 'gzip');
}
}
}));
会话管理
express-session
最常用的会话管理中间件,支持多种存储后端(内存、Redis、MongoDB等)。
const session = require('express-session');
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: true,
cookie: { secure: true, maxAge: 3600000 }
}));
app.get('/login', (req, res) => {
req.session.user = { id: 1, name: 'John' };
res.send('Logged in');
});
cookie-session
将会话数据直接存储在客户端 cookie 中,适合小型会话数据。
const cookieSession = require('cookie-session');
app.use(cookieSession({
name: 'session',
keys: ['key1', 'key2'],
maxAge: 24 * 60 * 60 * 1000 // 24小时
}));
比较:
express-session
适合存储大量会话数据cookie-session
更简单但受 cookie 大小限制
安全相关中间件
helmet
通过设置各种 HTTP 头来增强应用安全性。
const helmet = require('helmet');
app.use(helmet());
自定义配置:
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "trusted.cdn.com"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true
}
}));
csurf
CSRF 保护中间件(注意:Express 5 将移除该中间件)。
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
app.get('/form', csrfProtection, (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
app.post('/process', csrfProtection, (req, res) => {
// 验证 CSRF 令牌
res.send('Form processed');
});
日志记录
morgan
HTTP 请求日志记录器,支持多种预定义格式和自定义格式。
const morgan = require('morgan');
// 使用预定义格式
app.use(morgan('combined'));
// 自定义格式
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
// 只记录错误请求
app.use(morgan('combined', {
skip: (req, res) => res.statusCode < 400
}));
winston
更全面的日志解决方案,支持多传输方式和日志级别。
const winston = require('winston');
const expressWinston = require('express-winston');
// 请求日志
app.use(expressWinston.logger({
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'requests.log' })
],
format: winston.format.combine(
winston.format.colorize(),
winston.format.json()
),
meta: true,
msg: "HTTP {{req.method}} {{req.url}}"
}));
// 错误日志
app.use(expressWinston.errorLogger({
transports: [
new winston.transports.File({ filename: 'errors.log' })
]
}));
路由管理
express.Router
Express 内置的路由系统,支持模块化路由定义。
// routes/users.js
const router = express.Router();
router.get('/', (req, res) => {
res.send('User list');
});
router.get('/:id', (req, res) => {
res.send(`User ${req.params.id}`);
});
module.exports = router;
// app.js
const userRoutes = require('./routes/users');
app.use('/users', userRoutes);
express-promise-router
支持异步路由处理的增强版 Router。
const Router = require('express-promise-router');
const router = new Router();
router.get('/async', async (req, res) => {
const data = await someAsyncOperation();
res.json(data);
});
app.use(router);
错误处理
errorhandler
开发环境下的错误处理中间件。
const errorHandler = require('errorhandler');
if (process.env.NODE_ENV === 'development') {
app.use(errorHandler());
}
express-async-errors
简化异步路由的错误处理。
require('express-async-errors');
app.get('/async-error', async (req, res) => {
throw new Error('Something went wrong');
// 不需要 try/catch
});
// 全局错误处理
app.use((err, req, res, next) => {
console.error(err);
res.status(500).send('Something broke!');
});
性能优化
compression
响应压缩中间件,支持 gzip/deflate。
const compression = require('compression');
app.use(compression({
threshold: 1024, // 只压缩大于1KB的响应
filter: (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
}
}));
express-rate-limit
API 请求限流中间件。
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 每个IP限制100个请求
message: 'Too many requests from this IP, please try again later'
});
app.use('/api/', limiter);
数据库集成
connect-redis
Redis 会话存储适配器。
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
app.use(session({
store: new RedisStore({
host: 'localhost',
port: 6379,
ttl: 86400
}),
secret: 'your-secret-key',
resave: false,
saveUninitialized: false
}));
connect-mongo
MongoDB 会话存储适配器。
const MongoStore = require('connect-mongo');
app.use(session({
store: MongoStore.create({
mongoUrl: 'mongodb://localhost:27017/session_db',
ttl: 14 * 24 * 60 * 60 // 14天
}),
secret: 'your-secret-key'
}));
文件上传
multer
处理 multipart/form-data 类型的表单数据,主要用于文件上传。
const multer = require('multer');
// 内存存储
const upload = multer();
// 磁盘存储
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
cb(null, Date.now() + '-' + file.originalname);
}
});
const upload = multer({ storage });
// 单文件上传
app.post('/upload', upload.single('avatar'), (req, res) => {
console.log(req.file);
res.send('File uploaded');
});
// 多文件上传
app.post('/photos', upload.array('photos', 12), (req, res) => {
console.log(req.files);
res.send('Files uploaded');
});
API 文档生成
swagger-ui-express
为 Express 应用提供 Swagger UI 界面。
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
apidoc
通过代码注释生成 API 文档。
/**
* @api {get} /user/:id 获取用户信息
* @apiName GetUser
* @apiGroup User
*
* @apiParam {Number} id 用户唯一ID
*
* @apiSuccess {String} name 用户名
* @apiSuccess {Number} age 用户年龄
*/
app.get('/user/:id', (req, res) => {
// 实现代码
});
模板引擎
express-handlebars
Handlebars 模板引擎的 Express 集成。
const exphbs = require('express-handlebars');
app.engine('hbs', exphbs({
extname: '.hbs',
defaultLayout: 'main',
layoutsDir: path.join(__dirname, 'views/layouts'),
partialsDir: path.join(__dirname, 'views/partials')
}));
app.set('view engine', 'hbs');
app.get('/', (req, res) => {
res.render('home', { title: 'Home Page' });
});
pug
流行的 Pug (Jade) 模板引擎。
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));
app.get('/', (req, res) => {
res.render('index', { title: 'Pug Example', message: 'Hello Pug!' });
});
跨域处理
cors
处理跨域资源共享(CORS)的中间件。
const cors = require('cors');
// 简单使用
app.use(cors());
// 自定义配置
app.use(cors({
origin: ['https://example.com', 'https://api.example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Custom-Header'],
credentials: true,
maxAge: 86400
}));
// 路由级配置
app.get('/products/:id', cors(), (req, res) => {
res.json({ id: req.params.id });
});
测试相关
supertest
用于测试 HTTP 端点的库,常与测试框架配合使用。
const request = require('supertest');
const app = require('../app');
describe('GET /users', () => {
it('responds with JSON', (done) => {
request(app)
.get('/users')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
});
});
node-mocks-http
创建模拟的请求和响应对象用于测试中间件。
const httpMocks = require('node-mocks-http');
const middleware = require('../middleware/logger');
test('logger middleware should log request', () => {
const req = httpMocks.createRequest({
method: 'GET',
url: '/test'
});
const res = httpMocks.createResponse();
const next = jest.fn();
middleware(req, res, next);
expect(next).toHaveBeenCalled();
});
实用工具
express-validator
请求数据验证中间件。
const { body, validationResult } = require('express-validator');
app.post('/user',
body('username').isLength({ min: 5 }).trim().escape(),
body('email').isEmail().normalizeEmail(),
body('age').isInt({ min: 18 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// 处理有效数据
res.send('User created');
}
);
express-list-endpoints
列出应用中所有已注册的路由。
const listEndpoints = require('express-list-endpoints');
// 获取所有路由
const allRoutes = listEndpoints(app);
console.log(allRoutes);
// 输出示例:
// [
// { path: '/', methods: ['GET'] },
// { path: '/users', methods: ['GET', 'POST'] }
// ]
微服务相关
express-gateway
构建 API 网关的框架。
// gateway.config.yml
http:
port: 8080
apiEndpoints:
api:
host: localhost
paths: '/ip'
serviceEndpoints:
httpbin:
url: 'https://httpbin.org'
policies:
- proxy
pipelines:
default:
apiEndpoints:
- api
policies:
- proxy:
- action:
serviceEndpoint: httpbin
changeOrigin: true
express-http-proxy
HTTP 代理中间件。
const proxy = require('express-http-proxy');
app.use('/proxy', proxy('http://example.com', {
proxyReqPathResolver: (req) => {
return req.url;
},
userResDecorator: (proxyRes, proxyResData, userReq, userRes) => {
const data = JSON.parse(proxyResData.toString());
data.customField = 'proxied';
return JSON.stringify(data);
}
}));
实时通信
express-ws
为 Express 添加 WebSocket 支持。
const expressWs = require('express-ws')(app);
app.ws('/echo', (ws, req) => {
ws.on('message', (msg) => {
ws.send(msg);
});
});
// 同时支持HTTP和WebSocket
app.get('/echo', (req, res) => {
res.send('Use WebSocket endpoint');
});
socket.io
流行的实时通信库,与 Express 集成良好。
const http = require('http');
const socketIo = require('socket.io');
const server = http.createServer(app);
const io = socketIo(server);
io.on('connection', (socket) => {
console.log('New client connected');
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
server.listen(3000);
国际化
i18next-express-middleware
国际化(i18n)中间件。
const i18next = require('i18next');
const i18nextMiddleware = require('i18next-express-middleware');
i18next
.use(i18nextMiddleware.LanguageDetector)
.init({
fallbackLng: 'en',
resources: {
en: { translation: require('./locales/en.json') },
zh: { translation: require('./locales/zh.json') }
}
});
app.use(i18nextMiddleware.handle(i18next));
app.get('/', (req, res) => {
res.send(req.t('welcome_message'));
});
监控与指标
express-status-monitor
实时应用监控仪表盘。
const expressStatusMonitor = require('express-status-monitor');
app.use(expressStatusMonitor({
path: '/status',
spans: [
{ interval: 1, retention: 60 }, // 1分钟采样,保留60个数据点
{ interval: 5, retention: 60 },
{ interval: 15, retention: 60 }
],
chartVisibility: {
cpu: true,
mem: true,
load: true,
responseTime: true,
rps: true,
statusCodes: true
}
}));
prom-client
Prometheus 监控指标收集。
const promBundle = require('express-prom-bundle');
const metricsMiddleware = promBundle({
includeMethod: true,
includePath: true,
customLabels: { project_name: 'hello_world' },
promClient: {
collectDefaultMetrics: {
timeout: 1000
}
}
});
app.use(metricsMiddleware);
// 暴露指标端点
app.get('/metrics', (req, res) => {
res.set('Content-Type', promBundle.register.contentType);
res.end(promBundle.register.metrics());
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:中间件的复用与模块化
下一篇:中间件的性能影响分析