简介
每个实用的 API 都需要从客户端接收数据——URL 中的用户 ID、查询字符串中的筛选选项,或带有表单数据的 JSON 请求体。在构建 CRUD 端点之前,你需要准确了解 Express 将每项传入数据放在哪里,以及如何可靠地读取它们。
本课程将依次讲解三种主要的输入来源——URL 参数、查询字符串和请求体——然后将三者综合运用于一个简单资源的完整 CRUD 端点集合。
读取输入:参数、查询字符串与请求体
Express 将传入的请求数据解析为请求对象上的三个不同对象。
URL 参数是路径中的命名段。你可以在路由定义中用冒号声明它们,Express 会将它们暴露在 req.params 上。
javascript
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ requested: userId });
});
查询字符串出现在 URL 中问号之后,例如 /users?role=admin&limit=10。Express 会自动将其解析到 req.query。
javascript
app.get('/users', (req, res) => {
const { role, limit } = req.query;
res.json({ role, limit });
});
请求体承载客户端发送的结构化数据,最常见的是 JSON。Express 默认不会解析请求体——你需要在路由之前注册内置的 express.json() 中间件。
javascript
const express = require('express');
const app = express();
app.use(express.json());
一旦该中间件配置完成,POST 和 PUT 的负载就可以通过 req.body 访问。

构建完整的 CRUD API
为了聚焦于路由机制,下面的示例使用内存数组作为数据存储。在真实项目中,你应该将数组操作替换为数据库调用。
从数据和一个用于生成 ID 的辅助函数开始:
javascript
let users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
];
let nextId = 3;
创建——POST /users 读取请求体并推入一条新记录:
javascript
app.post('/users', (req, res) => {
const { name, role } = req.body;
if (!name || !role) {
return res.status(400).json({ error: 'name and role are required' });
}
const newUser = { id: nextId++, name, role };
users.push(newUser);
res.status(201).json(newUser);
});
读取全部——GET /users 支持通过查询字符串按角色进行可选筛选:
javascript
app.get('/users', (req, res) => {
const { role } = req.query;
const result = role ? users.filter(u => u.role === role) : users;
res.json(result);
});
读取单个——GET /users/:id 使用 req.params 查找单条记录:
javascript
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id === Number(req.params.id));
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
});
更新——PUT /users/:id 将参数(哪条记录)与请求体(新值)结合:
javascript
app.put('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === Number(req.params.id));
if (index === -1) return res.status(404).json({ error: 'User not found' });
const { name, role } = req.body;
users[index] = { ...users[index], ...(name && { name }), ...(role && { role }) };
res.json(users[index]);
});
删除——DELETE /users/:id 删除记录并返回 204 No Content:
javascript
app.delete('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === Number(req.params.id));
if (index === -1) return res.status(404).json({ error: 'User not found' });
users.splice(index, 1);
res.status(204).send();
});

常见错误
忘记使用 express.json() 是初学者最常遇到的困惑来源。如果 req.body 是 undefined,请检查中间件是否已注册,以及客户端是否发送了 Content-Type: application/json 头。
在比较之前没有将 req.params.id 转换为数字是另一个微妙的 bug。路由参数始终是字符串。严格相等比较字符串 "1" 和数字 1 总会返回 false,因此你的 find 或 findIndex 调用会静默地错过每条记录。
在发送响应后返回数据会导致 Express 抛出 "headers already sent" 错误。在条件语句中的 res 调用之前始终使用 return,如上面的示例所示。
小结
Express 将传入的请求数据拆分到三个对象中:req.params 用于 URL 段,req.query 用于查询字符串,req.body 用于解析后的 JSON 负载。注册 express.json() 中间件即可启用请求体解析。理解了这三个数据来源后,构建标准的 CRUD 端点就变成了将 HTTP 方法和状态码映射到正确的数据操作——POST 和 201 用于创建,GET 用于读取,PUT 用于更新,DELETE 配合 204 用于删除。