路由级中间件 #
一、路由级中间件概述 #
1.1 什么是路由级中间件? #
路由级中间件是绑定到Express Router实例上的中间件。使用 router.use() 或 router.METHOD() 方法绑定。
1.2 与应用级中间件的区别 #
| 特性 | 应用级中间件 | 路由级中间件 |
|---|---|---|
| 绑定对象 | app | router |
| 挂载方法 | app.use() | router.use() |
| 作用范围 | 整个应用 | 特定路由模块 |
| 灵活性 | 全局生效 | 模块独立 |
1.3 基本用法 #
javascript
const express = require('express');
const router = express.Router();
router.use((req, res, next) => {
console.log('路由级中间件');
next();
});
router.get('/users', (req, res) => {
res.json({ users: [] });
});
module.exports = router;
二、router.use() #
2.1 基本语法 #
javascript
router.use(path, callback)
2.2 路由模块中间件 #
javascript
const express = require('express');
const router = express.Router();
router.use((req, res, next) => {
console.log('所有该路由模块的请求都会经过这里');
next();
});
router.get('/', (req, res) => {
res.json({ message: '用户列表' });
});
router.get('/:id', (req, res) => {
res.json({ id: req.params.id });
});
module.exports = router;
2.3 路径匹配 #
javascript
router.use('/admin', (req, res, next) => {
console.log('Admin路由');
next();
});
router.get('/admin/dashboard', (req, res) => {
res.json({ message: '管理面板' });
});
三、认证中间件 #
3.1 基本认证 #
javascript
const express = require('express');
const router = express.Router();
const authMiddleware = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) {
return res.status(401).json({ error: '请先登录' });
}
try {
const decoded = verifyToken(token);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({ error: '无效的token' });
}
};
router.use(authMiddleware);
router.get('/profile', (req, res) => {
res.json(req.user);
});
module.exports = router;
3.2 可选认证 #
javascript
const optionalAuth = (req, res, next) => {
const token = req.headers['authorization'];
if (token) {
try {
const decoded = verifyToken(token);
req.user = decoded;
} catch (error) {
req.user = null;
}
}
next();
};
router.use(optionalAuth);
router.get('/posts', (req, res) => {
if (req.user) {
res.json({ posts: [], message: '个性化内容' });
} else {
res.json({ posts: [], message: '公共内容' });
}
});
3.3 角色权限 #
javascript
const checkRole = (...roles) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: '请先登录' });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: '无权限访问' });
}
next();
};
};
router.get('/admin', authMiddleware, checkRole('admin'), (req, res) => {
res.json({ message: '管理员页面' });
});
router.get('/dashboard', authMiddleware, checkRole('admin', 'editor'), (req, res) => {
res.json({ message: '仪表盘' });
});
四、验证中间件 #
4.1 数据验证 #
javascript
const { body, validationResult } = require('express-validator');
const validateUser = [
body('name').notEmpty().withMessage('用户名不能为空'),
body('email').isEmail().withMessage('请输入有效的邮箱'),
body('password').isLength({ min: 6 }).withMessage('密码至少6个字符'),
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
];
router.post('/users', validateUser, (req, res) => {
res.status(201).json(req.body);
});
4.2 参数验证 #
javascript
const { param, validationResult } = require('express-validator');
const validateId = [
param('id').isMongoId().withMessage('无效的ID格式'),
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
];
router.get('/users/:id', validateId, (req, res) => {
res.json({ id: req.params.id });
});
4.3 查询参数验证 #
javascript
const { query, validationResult } = require('express-validator');
const validatePagination = [
query('page').optional().isInt({ min: 1 }).toInt(),
query('limit').optional().isInt({ min: 1, max: 100 }).toInt(),
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
];
router.get('/posts', validatePagination, (req, res) => {
const { page = 1, limit = 10 } = req.query;
res.json({ page, limit, posts: [] });
});
五、资源加载中间件 #
5.1 加载用户 #
javascript
const loadUser = async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: '用户不存在' });
}
req.targetUser = user;
next();
} catch (error) {
next(error);
}
};
router.get('/users/:id', loadUser, (req, res) => {
res.json(req.targetUser);
});
router.put('/users/:id', loadUser, (req, res) => {
Object.assign(req.targetUser, req.body);
res.json(req.targetUser);
});
5.2 加载文章 #
javascript
const loadPost = async (req, res, next) => {
try {
const post = await Post.findById(req.params.postId);
if (!post) {
return res.status(404).json({ error: '文章不存在' });
}
req.post = post;
next();
} catch (error) {
next(error);
}
};
router.get('/posts/:postId', loadPost, (req, res) => {
res.json(req.post);
});
router.get('/posts/:postId/comments', loadPost, (req, res) => {
res.json(req.post.comments);
});
5.3 所有权检查 #
javascript
const checkOwnership = (req, res, next) => {
if (req.post.author.toString() !== req.user.id) {
return res.status(403).json({ error: '无权操作此资源' });
}
next();
};
router.put('/posts/:postId',
authMiddleware,
loadPost,
checkOwnership,
(req, res) => {
Object.assign(req.post, req.body);
res.json(req.post);
}
);
六、路由特定中间件 #
6.1 单路由中间件 #
javascript
router.get('/protected',
authMiddleware,
(req, res) => {
res.json({ user: req.user });
}
);
6.2 多个中间件 #
javascript
router.delete('/users/:id',
authMiddleware,
checkRole('admin'),
validateId,
loadUser,
(req, res) => {
res.json({ message: '删除成功' });
}
);
6.3 中间件数组 #
javascript
const middlewares = [
authMiddleware,
checkRole('admin'),
validateId
];
router.delete('/users/:id', middlewares, loadUser, (req, res) => {
res.json({ message: '删除成功' });
});
七、嵌套路由中间件 #
7.1 父路由中间件 #
javascript
const express = require('express');
const router = express.Router({ mergeParams: true });
router.use((req, res, next) => {
console.log('postId:', req.params.postId);
next();
});
router.get('/', (req, res) => {
res.json({
postId: req.params.postId,
comments: []
});
});
module.exports = router;
7.2 评论路由 #
javascript
const express = require('express');
const router = express.Router();
const commentsRouter = require('./comments');
router.use('/:postId/comments', commentsRouter);
router.get('/', (req, res) => {
res.json({ posts: [] });
});
module.exports = router;
八、完整示例 #
8.1 用户路由模块 #
javascript
const express = require('express');
const router = express.Router();
const { body, param, validationResult } = require('express-validator');
const User = require('../models/User');
const { auth, authorize } = require('../middlewares/auth');
const validate = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
};
const validateUser = [
body('name').notEmpty().trim().escape(),
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 6 }),
validate
];
const validateUserId = [
param('id').isMongoId(),
validate
];
const loadUser = async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: '用户不存在' });
}
req.targetUser = user;
next();
} catch (error) {
next(error);
}
};
router.get('/', auth, authorize('admin'), async (req, res, next) => {
try {
const users = await User.find().select('-password');
res.json(users);
} catch (error) {
next(error);
}
});
router.get('/:id', auth, validateUserId, loadUser, (req, res) => {
res.json(req.targetUser);
});
router.post('/', validateUser, async (req, res, next) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).json(user);
} catch (error) {
next(error);
}
});
router.put('/:id', auth, validateUserId, loadUser, async (req, res, next) => {
try {
Object.assign(req.targetUser, req.body);
await req.targetUser.save();
res.json(req.targetUser);
} catch (error) {
next(error);
}
});
router.delete('/:id', auth, authorize('admin'), validateUserId, loadUser, async (req, res, next) => {
try {
await req.targetUser.remove();
res.status(204).send();
} catch (error) {
next(error);
}
});
module.exports = router;
8.2 文章路由模块 #
javascript
const express = require('express');
const router = express.Router();
const Post = require('../models/Post');
const { auth } = require('../middlewares/auth');
router.get('/', async (req, res, next) => {
try {
const { page = 1, limit = 10 } = req.query;
const posts = await Post.find()
.skip((page - 1) * limit)
.limit(parseInt(limit));
res.json(posts);
} catch (error) {
next(error);
}
});
router.get('/:id', async (req, res, next) => {
try {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ error: '文章不存在' });
}
res.json(post);
} catch (error) {
next(error);
}
});
router.post('/', auth, async (req, res, next) => {
try {
const post = new Post({
...req.body,
author: req.user.id
});
await post.save();
res.status(201).json(post);
} catch (error) {
next(error);
}
});
router.put('/:id', auth, async (req, res, next) => {
try {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ error: '文章不存在' });
}
if (post.author.toString() !== req.user.id) {
return res.status(403).json({ error: '无权修改' });
}
Object.assign(post, req.body);
await post.save();
res.json(post);
} catch (error) {
next(error);
}
});
router.delete('/:id', auth, async (req, res, next) => {
try {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ error: '文章不存在' });
}
if (post.author.toString() !== req.user.id && req.user.role !== 'admin') {
return res.status(403).json({ error: '无权删除' });
}
await post.remove();
res.status(204).send();
} catch (error) {
next(error);
}
});
module.exports = router;
九、总结 #
路由级中间件要点:
| 方法 | 说明 |
|---|---|
| router.use() | 路由模块级中间件 |
| router.METHOD() | 路由特定中间件 |
| 中间件数组 | 多个中间件组合 |
| mergeParams | 嵌套路由参数合并 |
下一步,让我们学习错误处理中间件!
最后更新:2026-03-28