后端开发规范模板
阶段 4 模板:后端开发标准
文档信息
| 字段 |
值 |
| 项目名称 |
{项目名称} |
| 版本 |
1.0.0 |
| 创建日期 |
{日期} |
1. API 设计标准
1.1 API 风格
| 属性 |
值 |
| 风格 |
REST / GraphQL / gRPC |
| 基础 URL |
/api/v1 |
| 协议 |
仅 HTTPS |
1.2 URL 规范
| 规范 |
示例 |
描述 |
| 使用名词 |
/users, /orders |
资源用名词表示 |
| 复数形式 |
/users 而非 /user |
统一使用复数 |
| 嵌套资源 |
/users/{id}/orders |
最多 2 层 |
| 查询参数 |
?page=1&limit=20 |
过滤、分页 |
1.3 HTTP 方法
| 方法 |
用途 |
幂等 |
安全 |
| GET |
获取资源 |
是 |
是 |
| POST |
创建资源 |
否 |
否 |
| PUT |
全量更新 |
是 |
否 |
| PATCH |
部分更新 |
否 |
否 |
| DELETE |
删除资源 |
是 |
否 |
1.4 HTTP 状态码
| 状态码 |
含义 |
使用场景 |
| 200 |
成功 |
GET、PUT、PATCH 成功 |
| 201 |
已创建 |
POST 成功 |
| 204 |
无内容 |
DELETE 成功 |
| 400 |
错误请求 |
校验错误 |
| 401 |
未认证 |
缺少/无效认证 |
| 403 |
禁止访问 |
权限不足 |
| 404 |
未找到 |
资源不存在 |
| 409 |
冲突 |
重复/约束违反 |
| 422 |
无法处理 |
校验失败 |
| 429 |
请求过多 |
触发限流 |
| 500 |
服务器错误 |
未知错误 |
| 502 |
网关错误 |
上游故障 |
| 503 |
服务不可用 |
维护/过载 |
2. 请求/响应格式
2.1 请求头
Content-Type: application/json
Accept: application/json
Authorization: Bearer {token}
X-Request-ID: {uuid}
X-Correlation-ID: {uuid}
2.2 标准响应结构
成功响应
{
"data": {
// 响应数据
},
"meta": {
"requestId": "uuid",
"timestamp": "2024-01-15T10:30:00Z"
}
}
分页响应
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5,
"hasNext": true,
"hasPrev": false
},
"meta": {
"requestId": "uuid",
"timestamp": "2024-01-15T10:30:00Z"
}
}
错误响应
{
"error": {
"code": "VALIDATION_ERROR",
"message": "请求包含无效数据",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "必须是有效的邮箱地址"
}
],
"requestId": "uuid",
"timestamp": "2024-01-15T10:30:00Z"
}
}
2.3 错误码分类
| 前缀 |
分类 |
示例 |
AUTH_ |
认证 |
AUTH_TOKEN_EXPIRED, AUTH_INVALID_CREDENTIALS |
PERM_ |
授权 |
PERM_DENIED, PERM_INSUFFICIENT |
VAL_ |
校验 |
VAL_REQUIRED, VAL_INVALID_FORMAT, VAL_OUT_OF_RANGE |
RES_ |
资源 |
RES_NOT_FOUND, RES_ALREADY_EXISTS |
SYS_ |
系统 |
SYS_INTERNAL_ERROR, SYS_SERVICE_UNAVAILABLE |
3. 认证与授权
3.1 认证方式
| 属性 |
值 |
| 类型 |
JWT Bearer Token |
| 令牌有效期 |
访问令牌: 15分钟, 刷新令牌: 7天 |
| 算法 |
RS256 |
3.2 JWT 载荷
{
"sub": "user-uuid",
"iat": 1705312800,
"exp": 1705313700,
"iss": "your-app",
"aud": "your-app-api",
"roles": ["user", "admin"],
"permissions": ["read:users", "write:users"]
}
3.3 授权模型
| 模型 |
用途 |
| RBAC |
基于角色访问(admin, user, guest) |
| ABAC |
基于属性细粒度控制 |
| 资源所有权 |
用户只能访问自己的资源 |
3.4 权限中间件
// 权限检查示例
function requirePermission(permission: string) {
return async (req, res, next) => {
const user = req.user;
if (!user.permissions.includes(permission)) {
return res.status(403).json({
error: {
code: 'PERM_DENIED',
message: `缺少必要权限: ${permission}`
}
});
}
next();
};
}
// 使用
app.delete('/users/:id',
authenticate,
requirePermission('delete:users'),
deleteUser
);
4. 校验标准
4.1 输入校验层级
| 层级 |
职责 |
| 路由 |
Schema 校验(请求结构) |
| 服务 |
业务规则校验 |
| 仓储 |
数据完整性 |
4.2 校验库
使用统一的校验库(如 Zod, Joi, class-validator)。
// Zod 示例
const createUserSchema = z.object({
email: z.string().email(),
password: z.string().min(8).max(100),
name: z.string().min(1).max(100).optional()
});
// 在路由处理中使用
const validated = createUserSchema.parse(req.body);
4.3 常用校验规则
| 字段 |
规则 |
| 邮箱 |
有效格式,标准化(小写、去空格) |
| 密码 |
最少 8 字符,最多 100,复杂度规则 |
| UUID |
有效的 UUID v4 格式 |
| 日期 |
ISO 8601 格式 |
| 分页 |
page >= 1, limit 1-100 |
5. 错误处理
5.1 错误层级
class AppError extends Error {
constructor(
public code: string,
public message: string,
public statusCode: number = 500,
public details?: any[]
) {
super(message);
}
}
class ValidationError extends AppError {
constructor(details: ValidationErrorDetail[]) {
super('VALIDATION_ERROR', '校验失败', 400, details);
}
}
class NotFoundError extends AppError {
constructor(resource: string) {
super('RES_NOT_FOUND', `${resource} 不存在`, 404);
}
}
class UnauthorizedError extends AppError {
constructor(message: string = '未授权') {
super('AUTH_UNAUTHORIZED', message, 401);
}
}
5.2 全局错误处理器
app.use((err, req, res, next) => {
// 记录错误
logger.error({
error: err,
requestId: req.id,
path: req.path,
method: req.method
});
// 处理已知错误
if (err instanceof AppError) {
return res.status(err.statusCode).json({
error: {
code: err.code,
message: err.message,
details: err.details,
requestId: req.id,
timestamp: new Date().toISOString()
}
});
}
// 处理未知错误
return res.status(500).json({
error: {
code: 'SYS_INTERNAL_ERROR',
message: '发生未知错误',
requestId: req.id,
timestamp: new Date().toISOString()
}
});
});
6. 日志标准
6.1 日志级别
| 级别 |
使用场景 |
| ERROR |
异常、操作失败 |
| WARN |
可恢复问题、废弃用法 |
| INFO |
业务事件、请求开始/结束 |
| DEBUG |
详细诊断信息 |
| TRACE |
非常详细的调试(生产环境禁用) |
6.2 结构化日志格式
{
"timestamp": "2024-01-15T10:30:00.000Z",
"level": "INFO",
"message": "用户创建成功",
"context": {
"requestId": "uuid",
"userId": "uuid",
"module": "user-service"
},
"data": {
"userId": "new-user-uuid"
}
}
6.3 请求日志中间件
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
logger.info({
message: '请求完成',
context: {
requestId: req.id,
method: req.method,
path: req.path,
statusCode: res.statusCode,
duration: Date.now() - start
}
});
});
next();
});
7. 限流
7.1 限流配置
| 端点类型 |
限制 |
时间窗口 |
键 |
| 公开 API |
100 次 |
1 分钟 |
IP 地址 |
| 认证 API |
300 次 |
1 分钟 |
用户 ID |
| 认证接口 |
5 次 |
1 分钟 |
IP + 邮箱 |
| 密码重置 |
3 次 |
1 小时 |
邮箱 |
7.2 限流响应头
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1705313100
7.3 限流响应
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "请求过多,请稍后重试。",
"retryAfter": 60
}
}
8. 缓存策略
8.1 缓存层级
| 层级 |
技术 |
用途 |
| 应用层 |
内存 (LRU) |
高频、小数据 |
| 分布式 |
Redis |
共享数据、会话 |
| CDN |
CloudFront/Cloudflare |
静态资源、API 响应 |
8.2 缓存头
| 头 |
值 |
用途 |
Cache-Control |
max-age=300 |
客户端缓存 |
ETag |
"{hash}" |
条件请求 |
Last-Modified |
ISO 日期 |
条件请求 |
8.3 缓存失效
| 策略 |
触发时机 |
实现方式 |
| TTL |
基于时间 |
自动过期 |
| 事件驱动 |
更新时 |
发布失效事件 |
| 标签驱动 |
批量 |
标签关联键 |
9. 代码结构
9.1 目录结构
src/
├── modules/
│ ├── user/
│ │ ├── user.controller.ts
│ │ ├── user.service.ts
│ │ ├── user.repository.ts
│ │ ├── user.dto.ts
│ │ ├── user.entity.ts
│ │ └── user.test.ts
│ └── order/
│ └── ...
├── common/
│ ├── middleware/
│ ├── guards/
│ ├── decorators/
│ ├── filters/
│ └── interceptors/
├── config/
│ └── configuration.ts
├── database/
│ ├── migrations/
│ └── seeds/
└── main.ts
9.2 命名规范
| 类型 |
规范 |
示例 |
| 文件 |
kebab-case |
user-service.ts |
| 类 |
PascalCase |
UserService |
| 函数 |
camelCase |
getUserById |
| 常量 |
SCREAMING_SNAKE |
MAX_RETRY_COUNT |
| 接口 |
PascalCase + 前缀 |
IUserRepository |
9.3 依赖注入
// 定义接口
interface IUserRepository {
findById(id: string): Promise<User | null>;
}
// 实现
@Injectable()
class UserRepository implements IUserRepository {
constructor(private readonly db: DatabaseService) {}
async findById(id: string): Promise<User | null> {
return this.db.users.findUnique({ where: { id } });
}
}
// 服务
@Injectable()
class UserService {
constructor(
@Inject('IUserRepository')
private readonly userRepo: IUserRepository
) {}
}
10. 测试标准
10.1 测试类型
| 类型 |
覆盖目标 |
重点 |
| 单元测试 |
80% |
单个函数/方法 |
| 集成测试 |
60% |
API 端点、服务 |
| E2E 测试 |
关键路径 |
用户流程 |
10.2 测试结构
describe('UserService', () => {
describe('createUser', () => {
it('应该用有效数据创建用户', async () => {
// 准备
const dto = { email: 'test@example.com', password: 'password123' };
// 执行
const result = await userService.createUser(dto);
// 断言
expect(result.email).toBe(dto.email);
});
it('应该对无效邮箱抛出校验错误', async () => {
// ...
});
});
});
10.3 测试数据库
- 使用独立的测试数据库
- 测试间重置
- 使用工厂生成测试数据
11. 性能标准
11.1 响应时间目标
| 端点类型 |
P50 |
P95 |
P99 |
| 读取(简单) |
50ms |
100ms |
200ms |
| 读取(复杂) |
100ms |
300ms |
500ms |
| 写入 |
100ms |
300ms |
500ms |
| 批量 |
500ms |
1s |
2s |
11.2 数据库查询标准
| 规则 |
描述 |
| N+1 预防 |
使用预加载或批处理 |
| 索引使用 |
所有查询使用索引 |
| 分页 |
列表端点必须分页 |
| 连接池 |
使用连接池 |
11.3 异步处理
| 操作类型 |
策略 |
| 邮件发送 |
队列(后台) |
| 文件处理 |
队列(后台) |
| 报表生成 |
队列 + 轮询 |
| 实时更新 |
WebSocket |
12. 安全检查清单
12.1 输入安全
12.2 认证安全
12.3 数据安全
校验清单