名称: 后端基础 描述: 此技能用于审查API设计、REST约定和架构。适用于初级开发者构建API端点、Express路由、中间件、控制器或提问“这是否RESTful”、“检查我的端点”。
后端基础审查
“API是合同。破坏了它们,就破坏了信任。”
何时应用
在审查以下内容时激活此技能:
- API路由处理程序
- Express/Fastify/Hono中间件
- 数据库查询和模型
- 认证/授权逻辑
- 服务器端业务逻辑
审查清单
API设计
- [ ] RESTful: 路由是否遵循REST惯例?(GET用于读,POST用于创建等)
- [ ] 命名: 端点是否使用名词而不是动词?(
/users而不是/getUsers) - [ ] 版本控制: API是否已版本化以便未来更改?(
/api/v1/) - [ ] 状态码: 是否返回正确的HTTP状态码?
关注点分离
- [ ] 路由: 路由是否只处理HTTP相关事宜(请求/响应)?
- [ ] 控制器: 业务逻辑是否在控制器/服务中,而不是在路由中?
- [ ] 服务: 数据访问是否从业务逻辑中抽象出来?
- [ ] 模型: 模型是否只负责数据形状/验证?
错误处理
- [ ] Try/Catch: 异步操作是否正确包装?
- [ ] 错误响应: 错误是否返回适当的状态码?
- [ ] 日志记录: 错误是否记录上下文?
- [ ] 无泄露: 内部错误是否对客户端隐藏?
安全
- [ ] 输入验证: 所有输入在使用前是否都经过验证?
- [ ] 认证: 受保护的路由是否实际受到保护?
- [ ] 授权: 用户是否只能访问自己的数据?
- [ ] 速率限制: 端点是否受到滥用保护?
常见错误(反模式)
1. 肥胖路由
❌ app.post('/users', async (req, res) => {
// 100行的验证、业务逻辑、数据库查询
});
✅ app.post('/users', validateUser, userController.create);
2. 无输入验证
❌ const { email } = req.body;
await db.query(`SELECT * FROM users WHERE email = '${email}'`);
✅ const { email } = validateBody(req.body, userSchema);
await User.findByEmail(email); // 参数化
3. 错误状态码
❌ res.status(200).json({ error: '未找到' });
✅ res.status(404).json({ error: '用户未找到' });
4. 泄露内部错误
❌ catch (error) {
res.status(500).json({ error: error.message, stack: error.stack });
}
✅ catch (error) {
logger.error('用户创建失败', { error, userId });
res.status(500).json({ error: '出了点问题' });
}
苏格拉底式问题
向初级开发者提问这些问题,而不是直接给出答案:
- 架构: “如果我想从Express切换到Fastify,需要改变什么?”
- 验证: “如果有人发送格式错误的JSON会发生什么?”
- 认证: “你如何知道这个用户拥有这个资源?”
- 错误: “当数据库宕机时,客户端会看到什么?”
- 测试: “你如何独立测试这个端点?”
HTTP状态码参考
| 代码 | 何时使用 |
|---|---|
| 200 | 成功(带有主体) |
| 201 | 已创建(在POST之后) |
| 204 | 成功(无内容,在DELETE之后) |
| 400 | 错误请求(验证失败) |
| 401 | 未授权(未登录) |
| 403 | 禁止(已登录但不允许) |
| 404 | 未找到 |
| 409 | 冲突(重复资源) |
| 500 | 服务器错误(对客户端隐藏细节) |
架构层次
请求 → 路由 → 控制器 → 服务 → 仓库 → 数据库
↓
中间件(认证、验证、日志记录)
| 层次 | 职责 |
|---|---|
| 路由 | HTTP动词、路径、中间件链 |
| 控制器 | 请求/响应处理,调用服务 |
| 服务 | 业务逻辑,编排 |
| 仓库 | 数据访问,查询 |
需要指出的红旗
| 红旗 | 提问 |
|---|---|
| 路由处理程序中的SQL | “数据访问是否应该放在单独层中?” |
| 异步操作无try/catch | “如果失败了会发生什么?” |
| 直接使用req.body | “如果某人发送了意外字段怎么办?” |
| 硬编码机密信息 | “这在生产中如何工作?” |
| 列表端点无分页 | “如果有10,000条记录怎么办?” |