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删除资源