2. 基于 Express 实现路由分发与参数解析

基于 Express 实现路由分发与参数解析 学习卡片

Express 路由分发与参数解析

Express 的核心能力之一是把不同 URL 映射到不同处理函数。路径中的动态段用 :name 声明,通过 req.params 读取;查询字符串通过 req.query 读取。路由按注册顺序依次匹配,先命中的处理函数先执行,因此顺序会直接影响结果。

关键对象:app.get(path, handler)、req.params、req.query、req.path、req.method。

路由匹配顺序与参数来源

Express 路由匹配顺序与参数解析 客户端请求 GET /users/42?role=admin method=GET 路由注册栈(按注册顺序) ① app.get('/users/:id') 匹配 /users/42 → params.id=42 ② app.get('/users/admin') 匹配 /users/admin → 固定路径 ③ app.get('/search') 读取 req.query.q / req.query.limit ④ app.use(404 兜底) 未命中任何路由时返回 404 匹配规则 从上到下逐条尝试 先命中先执行,不继续向下 :id 会捕获任意段,需注意位置 参数解析结果 req.params { id: "42" } req.query { role: "admin" } req.path = "/users/42" 响应输出 200 OK Content-Type: application/json { "id": "42", "role": "admin" } ⚠ 若将 /users/:id 放在 /users/admin 之前,请求 /users/admin 会被 :id 捕获,admin 被当作 id 值,固定路由永远无法命中。 结论:固定路径应注册在动态参数路径之前。

完整可运行示例

下面代码定义四个路由,覆盖动态参数、固定路径、查询字符串和 404 兜底。启动后可用浏览器或 curl 依次访问验证。

// app.js
const express = require('express');
const app = express();
const PORT = 3000;

// ① 动态参数路由:/users/42 → req.params.id = "42"
app.get('/users/:id', (req, res) => {
  res.json({
    route: '/users/:id',
    params: req.params,          // { id: "42" }
    query: req.query,            // { role: "admin" }
    path: req.path               // "/users/42"
  });
});

// ② 固定路径路由:/users/admin
// 注意:必须注册在 /users/:id 之前,否则会被 :id 捕获
app.get('/users/admin', (req, res) => {
  res.json({ route: '/users/admin', message: '管理员页面' });
});

// ③ 查询字符串路由:/search?q=node&limit=5
app.get('/search', (req, res) => {
  const { q = '', limit = '10' } = req.query;
  res.json({
    route: '/search',
    keyword: q,
    limit: Number(limit),
    hasKeyword: q.length > 0
  });
});

// ④ 404 兜底:所有未匹配的请求
app.use((req, res) => {
  res.status(404).json({
    error: 'Not Found',
    method: req.method,
    path: req.path
  });
});

app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
});

验证与观察

请求 命中路由 关键输出
GET /users/42?role=admin ① /users/:id params.id="42",query.role="admin"
GET /users/admin ② /users/admin(若顺序正确) message="管理员页面"
GET /search?q=node&limit=5 ③ /search keyword="node",limit=5
GET /unknown ④ 404 兜底 status=404,error="Not Found"
把 /users/admin 移到 /users/:id 之前再请求 /users/admin,观察响应从“管理员页面”变为 params.id="admin",即可直观看到注册顺序对匹配结果的影响。
req.params 的值始终是字符串;req.query 的值也是字符串或字符串数组。需要数字时应显式转换,例如 Number(req.query.limit),否则后续计算可能得到意外结果。