Express 路由模式
使用 express.Router 实现模块化路由,涵盖路径参数、查询字符串、嵌套路由和异步处理器。
1. express.Router — 模块化路由
// routes/users.js
const { Router } = require('express');
const router = Router();
router.get('/', async (req, res) => {
const users = await User.findAll();
res.json(users);
});
router.post('/', async (req, res) => {
const user = await User.create(req.body);
res.status(201).json(user);
});
router.get('/:id', async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) return res.status(404).json({ error: '未找到' });
res.json(user);
});
module.exports = router;
// app.js — 挂载路由器
const usersRouter = require('./routes/users');
app.use('/api/users', usersRouter);
2. 路由参数
// 命名参数
app.get('/posts/:year/:month/:slug', (req, res) => {
const { year, month, slug } = req.params;
res.json({ year, month, slug });
});
// 正则约束 — 仅匹配数字 ID
app.get('/users/:id(\\d+)', (req, res) => {
res.json({ id: parseInt(req.params.id) });
});
// router.param — 参数预处理中间件
router.param('id', async (req, res, next, id) => {
req.targetUser = await User.findById(id);
if (!req.targetUser) return res.status(404).json({ error: '未找到' });
next();
});
3. 查询参数与请求数据
// GET /search?q=express&page=2&limit=20&sort=date:desc
app.get('/search', (req, res) => {
const { q = '', page = 1, limit = 10, sort = 'createdAt:asc' } = req.query;
const [sortField, sortOrder] = sort.split(':');
res.json({
query: q,
pagination: { page: +page, limit: +limit },
sort: { field: sortField, order: sortOrder },
});
});
4. 嵌套路由器
// routes/posts.js
const router = Router({ mergeParams: true });
router.get('/', async (req, res) => {
// mergeParams 使子路由可访问父路由参数
const posts = await Post.findByUser(req.params.userId);
res.json(posts);
});
module.exports = router;
// routes/users.js — 挂载子路由
const postsRouter = require('./posts');
router.use('/:userId/posts', postsRouter);
// 最终 URL: /api/users/:userId/posts
5. 异步处理器与链式路由
const wrap = fn => (req, res, next) => fn(req, res, next).catch(next);
// 同一路径链式注册多个方法
router.route('/items/:id')
.get(wrap(async (req, res) => {
const item = await Item.findById(req.params.id);
res.json(item);
}))
.put(wrap(async (req, res) => {
const item = await Item.update(req.params.id, req.body);
res.json(item);
}))
.delete(wrap(async (req, res) => {
await Item.delete(req.params.id);
res.status(204).end();
}));
6. HTTP 方法参考
| 方法 | 用途 | 请求体 | 幂等 |
|---|---|---|---|
| GET | 读取资源 | 无 | 是 |
| POST | 创建资源 | 有 | 否 |
| PUT | 替换资源 | 有 | 是 |
| PATCH | 部分更新 | 有 | 否 |
| DELETE | 删除资源 | 无 | 是 |