跳到主要内容

中间件

中间件是 Express.js 的核心概念,它是一个函数,可以访问请求对象、响应对象和下一个中间件函数。

中间件概念

const middleware = (req, res, next) => {
// 请求处理逻辑
next(); // 调用下一个中间件
};

中间件类型

应用级中间件

const express = require('express');
const app = express();

app.use((req, res, next) => {
console.log('请求时间:', new Date().toISOString());
next();
});

app.use('/api', (req, res, next) => {
console.log('API 请求');
next();
});

路由级中间件

app.get('/users/:id', 
(req, res, next) => {
if (req.params.id === '0') {
next('route');
} else {
next();
}
},
(req, res) => {
res.send('常规用户');
}
);

app.get('/users/:id', (req, res) => {
res.send('特殊用户');
});

错误处理中间件

app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: '服务器错误' });
});

内置中间件

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));

第三方中间件

npm install morgan helmet cors
const morgan = require('morgan');
const helmet = require('helmet');
const cors = require('cors');

app.use(morgan('dev'));
app.use(helmet());
app.use(cors());

常用中间件

日志中间件

const logger = (req, res, next) => {
const start = Date.now();

res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.url} ${res.statusCode} - ${duration}ms`);
});

next();
};

app.use(logger);

请求体解析

app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));

静态文件服务

app.use('/static', express.static('public'));
npm install cookie-parser
const cookieParser = require('cookie-parser');
app.use(cookieParser());

app.get('/', (req, res) => {
console.log('Cookies:', req.cookies);
});

Session 管理

npm install express-session
const session = require('express-session');

app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: false,
cookie: { secure: false }
}));

自定义中间件

认证中间件

const authMiddleware = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];

if (!token) {
return res.status(401).json({ error: '需要登录' });
}

try {
const decoded = verifyToken(token);
req.user = decoded;
next();
} catch (err) {
res.status(401).json({ error: 'Token 无效' });
}
};

app.use('/api/protected', authMiddleware);

权限中间件

const checkRole = (...roles) => {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: '权限不足' });
}
next();
};
};

app.delete('/users/:id', authMiddleware, checkRole('admin'), (req, res) => {
res.json({ message: '删除成功' });
});

限流中间件

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: { error: '请求过于频繁' }
});

app.use('/api', limiter);

中间件执行顺序

app.use((req, res, next) => {
console.log('1. 全局中间件');
next();
});

app.use('/api', (req, res, next) => {
console.log('2. API 中间件');
next();
});

app.get('/api/users', (req, res, next) => {
console.log('3. 路由中间件');
next();
}, (req, res) => {
console.log('4. 路由处理');
res.json({ users: [] });
});

中间件最佳实践

  1. 按顺序加载:错误处理中间件放在最后
  2. 异步错误处理:使用 express-async-errors 或包装函数
  3. 模块化:将中间件分离到独立文件
  4. 性能考虑:避免不必要的中间件