Express.js 中间件指南
Express.js 中间件完整参考,涵盖内置、第三方和自定义中间件,附带实用代码示例。
1. 中间件基础 — app.use()
中间件函数可访问 req、res 和 next,必须调用 next() 将控制权交给下一个中间件。
const express = require('express');
const app = express();
// 应用级中间件(每个请求都会执行)
app.use((req, res, next) => {
console.log(`${req.method} ${req.path} — ${Date.now()}`);
next(); // 必须调用 next() 或发送响应
});
// 路径范围中间件(仅对 /api/* 生效)
app.use('/api', (req, res, next) => {
req.apiVersion = 'v1';
next();
});
// 一次注册多个中间件
app.use(express.json(), express.urlencoded({ extended: true }));
app.listen(3000);
2. 自定义中间件模式
请求日志
// middleware/logger.js
function requestLogger(options = {}) {
return (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl} ${res.statusCode} ${duration}ms`);
});
next();
};
}
module.exports = requestLogger;
// 使用
app.use(requestLogger());
认证中间件
const jwt = require('jsonwebtoken');
function requireAuth(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: '缺少 token' });
}
try {
const token = authHeader.slice(7);
req.user = jwt.verify(token, process.env.JWT_SECRET);
next();
} catch (err) {
res.status(401).json({ error: 'token 无效' });
}
}
// 基于角色的工厂函数
function requireRole(...roles) {
return (req, res, next) => {
if (!roles.includes(req.user?.role)) {
return res.status(403).json({ error: '无权限' });
}
next();
};
}
// 使用
app.get('/admin', requireAuth, requireRole('admin'), (req, res) => {
res.json({ message: '欢迎管理员' });
});
3. 错误处理中间件
错误中间件接收 4 个参数:(err, req, res, next),必须在最后注册。
// 异步错误包装器 — 避免在每个路由中写 try/catch
const asyncHandler = fn => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next);
class AppError extends Error {
constructor(message, statusCode = 500) {
super(message);
this.statusCode = statusCode;
this.isOperational = true;
}
}
app.get('/users/:id', asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) throw new AppError('用户不存在', 404);
res.json(user);
}));
// 全局错误处理(必须放在最后)
app.use((err, req, res, next) => {
const status = err.statusCode || 500;
const message = err.isOperational ? err.message : '服务器内部错误';
res.status(status).json({ error: message });
});
4. CORS 中间件
const cors = require('cors');
// 简单配置 — 允许所有来源
app.use(cors());
// 生产环境配置
const corsOptions = {
origin: (origin, callback) => {
const allowed = ['https://app.example.com', 'https://admin.example.com'];
if (!origin || allowed.includes(origin)) {
callback(null, true);
} else {
callback(new Error('不允许的来源'));
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400,
};
app.use(cors(corsOptions));
5. Body-Parser 与 Helmet
const helmet = require('helmet');
// Helmet — 设置安全 HTTP 头
app.use(helmet());
// 精细配置
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", 'data:', 'https:'],
},
},
hsts: { maxAge: 31536000, includeSubDomains: true },
}));
// 请求体解析(Express 4.16+ 内置)
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true }));
6. 中间件执行顺序
| 顺序 | 中间件 | 作用 |
|---|---|---|
| 1 | helmet() | 安全头 — 最先执行 |
| 2 | cors() | CORS 头 |
| 3 | express.json() | 解析请求体 |
| 4 | rateLimit() | 限流 |
| 5 | requireAuth() | 身份认证 |
| 6 | 路由 | 业务逻辑 |
| 7 | errorHandler | 必须最后注册 |