常用中间件 #
一、请求解析中间件 #
1.1 express.json() #
解析JSON格式的请求体:
javascript
app.use(express.json());
app.post('/data', (req, res) => {
console.log(req.body);
res.json(req.body);
});
配置选项:
javascript
app.use(express.json({
limit: '10kb',
strict: true,
type: 'application/json'
}));
1.2 express.urlencoded() #
解析URL编码的请求体:
javascript
app.use(express.urlencoded({ extended: true }));
app.post('/form', (req, res) => {
console.log(req.body);
res.json(req.body);
});
配置选项:
javascript
app.use(express.urlencoded({
extended: true,
limit: '10kb',
parameterLimit: 1000
}));
1.3 express.raw() #
解析原始请求体:
javascript
app.use(express.raw({ type: 'application/octet-stream', limit: '10mb' }));
app.post('/raw', (req, res) => {
console.log(req.body);
res.send(req.body);
});
1.4 express.text() #
解析文本请求体:
javascript
app.use(express.text({ type: 'text/plain' }));
app.post('/text', (req, res) => {
console.log(req.body);
res.send(req.body);
});
1.5 multer(文件上传) #
bash
npm install multer
javascript
const multer = require('multer');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits: { fileSize: 5 * 1024 * 1024 },
fileFilter: (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (!allowedTypes.includes(file.mimetype)) {
return cb(new Error('不支持的文件类型'), false);
}
cb(null, true);
}
});
app.post('/upload', upload.single('avatar'), (req, res) => {
res.json({ file: req.file });
});
app.post('/photos', upload.array('photos', 5), (req, res) => {
res.json({ files: req.files });
});
app.post('/fields', upload.fields([
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]), (req, res) => {
res.json({ files: req.files });
});
二、安全中间件 #
2.1 helmet #
设置各种HTTP头以提高安全性:
bash
npm install helmet
javascript
const helmet = require('helmet');
app.use(helmet());
单独配置:
javascript
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "trusted-cdn.com"]
}
},
crossOriginEmbedderPolicy: false
}));
helmet包含的安全头:
| 中间件 | 说明 |
|---|---|
| contentSecurityPolicy | 内容安全策略 |
| crossOriginEmbedderPolicy | 跨域嵌入策略 |
| crossOriginOpenerPolicy | 跨域打开策略 |
| crossOriginResourcePolicy | 跨域资源策略 |
| dnsPrefetchControl | DNS预取控制 |
| frameguard | 防止点击劫持 |
| hidePoweredBy | 隐藏X-Powered-By |
| hsts | HTTP严格传输安全 |
| ieNoOpen | IE下载保护 |
| noSniff | 防止MIME类型嗅探 |
| originAgentCluster | Origin代理集群 |
| permittedCrossDomainPolicies | 跨域策略 |
| referrerPolicy | Referrer策略 |
| xssFilter | XSS过滤器 |
2.2 cors #
处理跨域资源共享:
bash
npm install cors
javascript
const cors = require('cors');
app.use(cors());
配置选项:
javascript
app.use(cors({
origin: 'https://example.com',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400
}));
动态origin:
javascript
app.use(cors({
origin: (origin, callback) => {
const allowedOrigins = ['https://example.com', 'https://api.example.com'];
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('不允许的来源'));
}
}
}));
2.3 express-rate-limit #
请求限流:
bash
npm install express-rate-limit
javascript
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: { error: '请求过于频繁,请稍后再试' },
standardHeaders: true,
legacyHeaders: false
});
app.use('/api', limiter);
不同路由不同限制:
javascript
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
const loginLimiter = rateLimit({
windowMs: 60 * 60 * 1000,
max: 5,
message: '登录尝试过多,请1小时后再试'
});
app.use('/api', apiLimiter);
app.use('/auth/login', loginLimiter);
三、日志中间件 #
3.1 morgan #
HTTP请求日志:
bash
npm install morgan
javascript
const morgan = require('morgan');
app.use(morgan('dev'));
日志格式:
| 格式 | 说明 |
|---|---|
| combined | Apache标准格式 |
| common | Apache通用格式 |
| dev | 开发格式(彩色) |
| short | 短格式 |
| tiny | 最短格式 |
自定义格式:
javascript
morgan.token('user-id', (req) => req.user?.id || 'anonymous');
app.use(morgan(':method :url :status :response-time ms - :user-id'));
写入文件:
javascript
const fs = require('fs');
const path = require('path');
const accessLogStream = fs.createWriteStream(
path.join(__dirname, 'access.log'),
{ flags: 'a' }
);
app.use(morgan('combined', { stream: accessLogStream }));
3.2 winston #
通用日志库:
bash
npm install winston
javascript
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
app.use((req, res, next) => {
logger.info(`${req.method} ${req.url}`);
next();
});
四、性能中间件 #
4.1 compression #
响应压缩:
bash
npm install compression
javascript
const compression = require('compression');
app.use(compression());
配置选项:
javascript
app.use(compression({
filter: (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
},
threshold: 1024,
level: 6
}));
4.2 response-time #
添加响应时间头:
bash
npm install response-time
javascript
const responseTime = require('response-time');
app.use(responseTime());
五、会话和认证中间件 #
5.1 cookie-parser #
Cookie解析:
bash
npm install cookie-parser
javascript
const cookieParser = require('cookie-parser');
app.use(cookieParser());
app.use(cookieParser('secret-key'));
app.get('/', (req, res) => {
console.log('Cookies:', req.cookies);
console.log('Signed Cookies:', req.signedCookies);
res.send('OK');
});
app.get('/set-cookie', (req, res) => {
res.cookie('name', 'express', {
maxAge: 900000,
httpOnly: true,
signed: true
});
res.send('Cookie已设置');
});
5.2 express-session #
会话管理:
bash
npm install express-session
javascript
const session = require('express-session');
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
maxAge: 24 * 60 * 60 * 1000
}
}));
app.get('/login', (req, res) => {
req.session.userId = 1;
res.send('已登录');
});
app.get('/profile', (req, res) => {
if (!req.session.userId) {
return res.status(401).send('请先登录');
}
res.json({ userId: req.session.userId });
});
5.3 passport #
认证中间件:
bash
npm install passport passport-local
javascript
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(async (username, password, done) => {
try {
const user = await User.findOne({ username });
if (!user || !user.comparePassword(password)) {
return done(null, false, { message: '用户名或密码错误' });
}
return done(null, user);
} catch (error) {
return done(error);
}
}));
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findById(id);
done(null, user);
} catch (error) {
done(error);
}
});
app.use(session({ secret: 'secret' }));
app.use(passport.initialize());
app.use(passport.session());
app.post('/login', passport.authenticate('local'), (req, res) => {
res.json({ user: req.user });
});
六、数据验证中间件 #
6.1 express-validator #
请求数据验证:
bash
npm install express-validator
javascript
const { body, param, query, validationResult } = require('express-validator');
const validate = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
};
app.post('/users', [
body('name').notEmpty().withMessage('用户名不能为空').trim().escape(),
body('email').isEmail().withMessage('请输入有效的邮箱').normalizeEmail(),
body('password').isLength({ min: 6 }).withMessage('密码至少6个字符'),
body('age').optional().isInt({ min: 0, max: 150 }).toInt(),
validate
], (req, res) => {
res.status(201).json(req.body);
});
app.get('/users/:id', [
param('id').isMongoId().withMessage('无效的ID'),
validate
], (req, res) => {
res.json({ id: req.params.id });
});
app.get('/search', [
query('q').notEmpty().withMessage('搜索关键词不能为空'),
query('page').optional().isInt({ min: 1 }).toInt(),
query('limit').optional().isInt({ min: 1, max: 100 }).toInt(),
validate
], (req, res) => {
res.json(req.query);
});
七、静态文件中间件 #
7.1 express.static #
javascript
app.use(express.static('public'));
app.use('/static', express.static('public'));
app.use('/uploads', express.static('uploads', {
maxAge: '1d',
etag: false
}));
7.2 serve-favicon #
网站图标:
bash
npm install serve-favicon
javascript
const favicon = require('serve-favicon');
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
八、完整配置示例 #
javascript
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const morgan = require('morgan');
const compression = require('compression');
const rateLimit = require('express-rate-limit');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const app = express();
app.set('trust proxy', true);
app.use(helmet());
app.use(cors({
origin: process.env.CORS_ORIGIN || '*',
credentials: true
}));
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
} else {
app.use(morgan('combined'));
}
app.use(compression());
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false
});
app.use('/api', limiter);
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000
}
}));
app.use(express.static('public'));
app.get('/api/health', (req, res) => {
res.json({ status: 'ok' });
});
app.use((req, res) => {
res.status(404).json({ error: '路由未找到' });
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: '服务器错误' });
});
module.exports = app;
九、总结 #
常用中间件一览:
| 类别 | 中间件 | 用途 |
|---|---|---|
| 请求解析 | express.json | JSON解析 |
| 请求解析 | multer | 文件上传 |
| 安全 | helmet | 安全头设置 |
| 安全 | cors | 跨域处理 |
| 安全 | express-rate-limit | 请求限流 |
| 日志 | morgan | HTTP日志 |
| 性能 | compression | 响应压缩 |
| 会话 | express-session | 会话管理 |
| 认证 | passport | 用户认证 |
| 验证 | express-validator | 数据验证 |
下一步,让我们学习请求与响应对象!
最后更新:2026-03-28