# TYAPI Server API 开发规范 ## 🏗️ 项目架构概览 本项目采用 **DDD(领域驱动设计)** + **Clean Architecture** + **事件驱动架构**,基于 Gin 框架构建的企业级后端 API 服务。 ## 📋 目录结构规范 ``` internal/ ├── domains/ # 领域层 │ └── user/ # 用户领域 │ ├── dto/ # 数据传输对象 │ ├── entities/ # 实体 │ ├── events/ # 领域事件 │ ├── handlers/ # HTTP处理器 │ ├── repositories/ # 仓储接口实现 │ ├── routes/ # 路由配置 │ ├── services/ # 领域服务 │ └── validators/ # 验证器 ├── shared/ # 共享基础设施 │ ├── interfaces/ # 接口定义 │ ├── middleware/ # 中间件 │ ├── http/ # HTTP基础组件 │ └── ... └── config/ # 配置管理 ``` ## 🎯 业务分层架构 ### 1. 控制器层 (Handlers) ```go // internal/domains/user/handlers/user_handler.go type UserHandler struct { userService *services.UserService // 注入领域服务 response interfaces.ResponseBuilder // 统一响应构建器 validator interfaces.RequestValidator // 请求验证器 logger *zap.Logger // 结构化日志 jwtAuth *middleware.JWTAuthMiddleware // JWT认证 } // 标准CRUD处理器方法 func (h *UserHandler) Create(c *gin.Context) { var req dto.CreateUserRequest // 1. 请求验证 if err := h.validator.BindAndValidate(c, &req); err != nil { return // 验证器已处理响应 } // 2. 调用领域服务 user, err := h.userService.Create(c.Request.Context(), &req) if err != nil { h.logger.Error("Failed to create user", zap.Error(err)) h.response.BadRequest(c, err.Error()) return } // 3. 统一响应格式 response := dto.FromEntity(user) h.response.Created(c, response, "User created successfully") } ``` ### 2. 服务层 (Services) ```go // internal/domains/user/services/user_service.go type UserService struct { repo *repositories.UserRepository // 数据访问 eventBus interfaces.EventBus // 事件总线 logger *zap.Logger // 日志 } func (s *UserService) Create(ctx context.Context, req *dto.CreateUserRequest) (*entities.User, error) { // 1. 业务规则验证 if err := s.validateCreateUser(req); err != nil { return nil, err } // 2. 实体创建 user := entities.NewUser(req.Username, req.Email, req.Password) // 3. 数据持久化 if err := s.repo.Create(ctx, user); err != nil { return nil, err } // 4. 发布领域事件 event := events.NewUserCreatedEvent(user.ID, user.Username, user.Email) s.eventBus.PublishAsync(ctx, event) return user, nil } ``` ### 3. 仓储层 (Repositories) ```go // internal/domains/user/repositories/user_repository.go type UserRepository struct { db *gorm.DB // 数据库连接 cache interfaces.CacheService // 缓存服务 logger *zap.Logger // 日志 } func (r *UserRepository) Create(ctx context.Context, user *entities.User) error { // 使用事务确保数据一致性 return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { if err := tx.Create(user).Error; err != nil { return err } // 清除相关缓存 r.cache.Delete(ctx, fmt.Sprintf("user:count")) return nil }) } ``` ### 4. DTO 层 (数据传输对象) ```go // internal/domains/user/dto/user_dto.go type CreateUserRequest struct { Username string `json:"username" binding:"required,min=3,max=50" validate:"username"` Email string `json:"email" binding:"required,email" validate:"email"` Password string `json:"password" binding:"required,min=8" validate:"password"` DisplayName string `json:"display_name" binding:"max=100"` } type UserResponse struct { ID string `json:"id"` Username string `json:"username"` Email string `json:"email"` DisplayName string `json:"display_name"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // 实体转换函数 func FromEntity(user *entities.User) *UserResponse { return &UserResponse{ ID: user.ID, Username: user.Username, Email: user.Email, DisplayName: user.DisplayName, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, } } ``` ## 🛣️ 路由配置规范 ### 1. DDD 领域路由设计模式 ```go // internal/domains/user/routes/user_routes.go type UserRoutes struct { handler *handlers.UserHandler jwtAuth *middleware.JWTAuthMiddleware } func (r *UserRoutes) RegisterRoutes(router *gin.Engine) { // API版本组 v1 := router.Group("/api/v1") // 🏢 用户域路由组 - 按域名组织 users := v1.Group("/users") { // 🌍 公开路由(不需要认证) users.POST("/send-code", r.handler.SendCode) // 发送验证码 users.POST("/register", r.handler.Register) // 用户注册 users.POST("/login", r.handler.Login) // 用户登录 // 🔐 需要认证的路由 authenticated := users.Group("") authenticated.Use(r.jwtAuth.Handle()) { authenticated.GET("/me", r.handler.GetProfile) // 获取当前用户信息 authenticated.PUT("/me/password", r.handler.ChangePassword) // 修改密码 // 未来扩展示例: // authenticated.PUT("/me", r.handler.UpdateProfile) // 更新用户信息 // authenticated.DELETE("/me", r.handler.DeleteAccount) // 删除账户 // authenticated.GET("/me/sessions", r.handler.GetSessions) // 获取登录会话 } } // 📱 SMS验证码域路由组(如果需要单独管理SMS) sms := v1.Group("/sms") { sms.POST("/send", r.handler.SendCode) // 发送验证码 // 未来可以添加: // sms.POST("/verify", r.handler.VerifyCode) // 验证验证码 } } ``` ### 2. DDD 多域路由架构 ```go // 按域组织路由,支持横向扩展 func (r *UserRoutes) RegisterRoutes(router *gin.Engine) { v1 := router.Group("/api/v1") // 👥 用户域 users := v1.Group("/users") // 📦 订单域 orders := v1.Group("/orders") // 🛍️ 商品域 products := v1.Group("/products") // 💰 支付域 payments := v1.Group("/payments") } // 多级权限路由分层 users := v1.Group("/users") { // Level 1: 公开路由 users.POST("/register", r.handler.Register) users.POST("/login", r.handler.Login) // Level 2: 用户认证路由 authenticated := users.Group("") authenticated.Use(r.jwtAuth.Handle()) { authenticated.GET("/me", r.handler.GetProfile) } // Level 3: 管理员路由 admin := users.Group("/admin") admin.Use(r.jwtAuth.Handle(), r.adminAuth.Handle()) { admin.GET("", r.handler.AdminList) admin.DELETE("/:id", r.handler.AdminDelete) } } ``` ### 3. DDD 路由命名最佳实践 #### ✅ **推荐做法** - 领域导向设计: ```go // 🏢 按业务域划分路由 /api/v1/users/* # 用户域的所有操作 /api/v1/orders/* # 订单域的所有操作 /api/v1/products/* # 商品域的所有操作 /api/v1/payments/* # 支付域的所有操作 // 📋 资源操作使用名词复数 POST /api/v1/users/register # 用户注册 POST /api/v1/users/login # 用户登录 GET /api/v1/users/me # 获取当前用户 PUT /api/v1/users/me/password # 修改当前用户密码 // 🔗 体现资源关系的嵌套路径 GET /api/v1/users/me/orders # 获取当前用户的订单 GET /api/v1/orders/123/items # 获取订单的商品项目 POST /api/v1/products/456/reviews # 为商品添加评论 ``` #### ❌ **避免的做法** - 技术导向设计: ```go // ❌ 技术导向路径 /api/v1/auth/* # 混合了多个域的认证操作 /api/v1/service/* # 不明确的服务路径 /api/v1/api/* # 冗余的api前缀 // ❌ 动词路径 /api/v1/getUserInfo # 应该用 GET /users/me /api/v1/changeUserPassword # 应该用 PUT /users/me/password /api/v1/deleteUserAccount # 应该用 DELETE /users/me // ❌ 混合域概念 /api/v1/userorders # 应该分离为 /users/me/orders /api/v1/authprofile # 应该分离为 /users/me ``` ## 🔐 权限控制体系 ### 1. JWT 认证中间件 ```go // 强制认证中间件 type JWTAuthMiddleware struct { config *config.Config logger *zap.Logger } // 可选认证中间件(支持游客访问) type OptionalAuthMiddleware struct { jwtAuth *JWTAuthMiddleware } // 使用方式 protected.Use(r.jwtAuth.Handle()) // 强制认证 public.Use(r.optionalAuth.Handle()) // 可选认证 ``` ### 2. 权限验证模式 ```go // 在Handler中获取当前用户 func (h *UserHandler) getCurrentUserID(c *gin.Context) string { userID, exists := c.Get("user_id") if !exists { return "" } return userID.(string) } // 权限检查示例 func (h *UserHandler) UpdateProfile(c *gin.Context) { userID := h.getCurrentUserID(c) if userID == "" { h.response.Unauthorized(c, "User not authenticated") return } // 业务逻辑... } ``` ### 3. 权限级别定义 - **Public**: 公开接口,无需认证 - **User**: 需要用户登录 - **Admin**: 需要管理员权限 - **Owner**: 需要资源所有者权限 ## 📝 API 响应规范 ### 1. 统一响应格式 (APIResponse 结构) ```go // 标准API响应结构 type APIResponse struct { Success bool `json:"success"` // 操作是否成功 Message string `json:"message"` // 响应消息(中文) Data interface{} `json:"data,omitempty"` // 响应数据 Errors interface{} `json:"errors,omitempty"` // 错误详情 Pagination *PaginationMeta `json:"pagination,omitempty"` // 分页信息 Meta map[string]interface{} `json:"meta,omitempty"` // 元数据 RequestID string `json:"request_id"` // 请求追踪ID Timestamp int64 `json:"timestamp"` // Unix时间戳 } // 分页元数据结构 type PaginationMeta struct { Page int `json:"page"` // 当前页码 PageSize int `json:"page_size"` // 每页大小 Total int64 `json:"total"` // 总记录数 TotalPages int `json:"total_pages"` // 总页数 HasNext bool `json:"has_next"` // 是否有下一页 HasPrev bool `json:"has_prev"` // 是否有上一页 } ``` ### 2. 成功响应格式示例 ```json // 查询成功响应 (200 OK) { "success": true, "message": "获取成功", "data": { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, "request_id": "req_123456789", "timestamp": 1704067200 } // 创建成功响应 (201 Created) { "success": true, "message": "用户注册成功", "data": { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, "request_id": "req_123456789", "timestamp": 1704067200 } // 登录成功响应 (200 OK) { "success": true, "message": "登录成功", "data": { "user": { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 86400, "login_method": "password" }, "request_id": "req_123456789", "timestamp": 1704067200 } // 分页响应 (200 OK) { "success": true, "message": "获取成功", "data": [ { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z" } ], "pagination": { "page": 1, "page_size": 10, "total": 100, "total_pages": 10, "has_next": true, "has_prev": false }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` ### 3. 错误响应格式示例 ```json // 参数验证错误 (400 Bad Request) { "success": false, "message": "请求参数错误", "errors": { "phone": ["手机号必须为11位数字"], "password": ["密码长度至少6位"], "confirm_password": ["确认密码必须与密码一致"] }, "request_id": "req_123456789", "timestamp": 1704067200 } // 验证码错误 (422 Unprocessable Entity) { "success": false, "message": "验证失败", "errors": { "phone": ["手机号必须为11位数字"], "code": ["验证码必须为6位数字"] }, "request_id": "req_123456789", "timestamp": 1704067200 } // 业务逻辑错误 (400 Bad Request) { "success": false, "message": "手机号已存在", "request_id": "req_123456789", "timestamp": 1704067200 } // 认证错误 (401 Unauthorized) { "success": false, "message": "用户未登录或token已过期", "request_id": "req_123456789", "timestamp": 1704067200 } // 权限错误 (403 Forbidden) { "success": false, "message": "权限不足,无法访问此资源", "request_id": "req_123456789", "timestamp": 1704067200 } // 资源不存在 (404 Not Found) { "success": false, "message": "请求的资源不存在", "request_id": "req_123456789", "timestamp": 1704067200 } // 资源冲突 (409 Conflict) { "success": false, "message": "手机号已被注册", "request_id": "req_123456789", "timestamp": 1704067200 } // 限流错误 (429 Too Many Requests) { "success": false, "message": "请求过于频繁,请稍后再试", "meta": { "retry_after": "60s" }, "request_id": "req_123456789", "timestamp": 1704067200 } // 服务器错误 (500 Internal Server Error) { "success": false, "message": "服务器内部错误", "request_id": "req_123456789", "timestamp": 1704067200 } ``` ### 🚦 限流中间件和 TooManyRequests 详解 #### 限流配置 ```yaml # config.yaml 限流配置 ratelimit: requests: 1000 # 每个时间窗口允许的请求数 window: 60s # 时间窗口大小 burst: 200 # 突发请求允许数 ``` #### 限流中间件实现 ```go // RateLimitMiddleware 限流中间件(修复后的版本) type RateLimitMiddleware struct { config *config.Config response interfaces.ResponseBuilder // ✅ 使用统一响应格式 limiters map[string]*rate.Limiter mutex sync.RWMutex } // Handle 限流处理逻辑 func (m *RateLimitMiddleware) Handle() gin.HandlerFunc { return func(c *gin.Context) { clientID := m.getClientID(c) // 获取客户端ID(通常是IP地址) limiter := m.getLimiter(clientID) if !limiter.Allow() { // 添加限流头部信息 c.Header("X-RateLimit-Limit", fmt.Sprintf("%d", m.config.RateLimit.Requests)) c.Header("X-RateLimit-Window", m.config.RateLimit.Window.String()) c.Header("Retry-After", "60") // ✅ 使用统一的TooManyRequests响应格式(修复前是c.JSON) m.response.TooManyRequests(c, "请求过于频繁,请稍后再试") c.Abort() return } c.Next() } } ``` #### 多层限流保护 ```go // 🔹 1. 全局IP限流(中间件层) // 通过RateLimitMiddleware自动处理,返回429状态码 // 🔹 2. 短信发送限流(业务层) func (s *SMSCodeService) checkRateLimit(ctx context.Context, phone string) error { // 最小发送间隔检查 lastSentKey := fmt.Sprintf("sms:last_sent:%s", phone) if lastSent exists && now.Sub(lastSent) < s.config.RateLimit.MinInterval { return fmt.Errorf("请等待 %v 后再试", s.config.RateLimit.MinInterval) } // 每小时发送限制 hourlyKey := fmt.Sprintf("sms:hourly:%s:%s", phone, now.Format("2006010215")) if hourlyCount >= s.config.RateLimit.HourlyLimit { return fmt.Errorf("每小时最多发送 %d 条短信", s.config.RateLimit.HourlyLimit) } return nil } // 🔹 3. Handler层限流错误处理 func (h *UserHandler) SendSMSCode(c *gin.Context) { err := h.smsCodeService.SendCode(ctx, &req) if err != nil { // 检查是否是限流错误 if strings.Contains(err.Error(), "请等待") || strings.Contains(err.Error(), "最多发送") { // ✅ 使用TooManyRequests响应 h.response.TooManyRequests(c, err.Error()) return } h.response.BadRequest(c, err.Error()) return } h.response.Success(c, nil, "验证码发送成功") } ``` #### 限流响应示例 **中间件层限流**(全局 IP 限流): ```json { "success": false, "message": "请求过于频繁,请稍后再试", "meta": { "retry_after": "60s" }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` **业务层限流**(短信发送限流): ```json { "success": false, "message": "请等待 60 秒后再试", "meta": { "retry_after": "60s" }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` #### TooManyRequests 使用场景 - 🚫 **全局限流**: IP 请求频率限制 - 📱 **短信限流**: 验证码发送频率限制 - 🔐 **登录限流**: 防止暴力破解 - 📧 **邮件限流**: 邮件发送频率限制 - �� **搜索限流**: 防止恶意搜索 ### 4. ResponseBuilder 响应构建器使用 ```go // 成功响应 h.response.Success(c, data, "获取成功") h.response.Created(c, data, "创建成功") // 客户端错误响应 h.response.BadRequest(c, "请求参数错误", validationErrors) h.response.Unauthorized(c, "用户未登录或token已过期") h.response.Forbidden(c, "权限不足,无法访问此资源") h.response.NotFound(c, "请求的资源不存在") h.response.Conflict(c, "手机号已被注册") h.response.ValidationError(c, validationErrors) h.response.TooManyRequests(c, "请求过于频繁,请稍后再试") // 服务器错误响应 h.response.InternalError(c, "服务器内部错误") // 分页响应 h.response.Paginated(c, data, pagination) // 自定义响应 h.response.CustomResponse(c, statusCode, data) ``` ### 5. 错误处理分层架构 ```go // 1. Handler层 - HTTP错误处理 func (h *UserHandler) Register(c *gin.Context) { var req dto.RegisterRequest // 验证请求参数 if err := h.validator.BindAndValidate(c, &req); err != nil { return // 验证器已处理响应,直接返回 } // 调用业务服务 user, err := h.userService.Register(c.Request.Context(), &req) if err != nil { h.logger.Error("用户注册失败", zap.Error(err)) // 根据错误类型返回相应响应 switch { case strings.Contains(err.Error(), "手机号已存在"): h.response.Conflict(c, "手机号已被注册") case strings.Contains(err.Error(), "验证码错误"): h.response.BadRequest(c, "验证码错误或已过期") default: h.response.InternalError(c, "注册失败,请稍后重试") } return } // 成功响应 response := dto.FromEntity(user) h.response.Created(c, response, "用户注册成功") } // 2. 验证器层 - 参数验证错误 func (v *RequestValidator) BindAndValidate(c *gin.Context, dto interface{}) error { // 绑定请求体 if err := c.ShouldBindJSON(dto); err != nil { v.response.BadRequest(c, "请求体格式错误", err.Error()) return err } // 验证数据 if err := v.validator.Struct(dto); err != nil { validationErrors := v.formatValidationErrors(err) v.response.ValidationError(c, validationErrors) return err } return nil } // 3. 业务服务层 - 业务逻辑错误 func (s *UserService) Register(ctx context.Context, req *dto.RegisterRequest) (*entities.User, error) { // 验证手机号格式 if !s.isValidPhone(req.Phone) { return nil, fmt.Errorf("手机号格式不正确") } // 检查手机号是否已存在 if err := s.checkPhoneDuplicate(ctx, req.Phone); err != nil { return nil, fmt.Errorf("手机号已存在") } // 验证验证码 if err := s.smsCodeService.VerifyCode(ctx, req.Phone, req.Code, entities.SMSSceneRegister); err != nil { return nil, fmt.Errorf("验证码错误或已过期") } // 创建用户... return user, nil } ``` ## 🔄 RESTful API 设计规范 ### 1. DDD 架构下的 URL 设计规范 ```bash # 🏢 领域驱动的资源设计 GET /api/v1/users/me # 获取当前用户信息 PUT /api/v1/users/me # 更新当前用户信息 DELETE /api/v1/users/me # 删除当前用户账户 # 🔐 认证相关操作(仍在用户域内) POST /api/v1/users/register # 用户注册 POST /api/v1/users/login # 用户登录 POST /api/v1/users/logout # 用户登出 POST /api/v1/users/send-code # 发送验证码 # 📱 SMS验证码域操作 POST /api/v1/sms/send # 发送验证码 POST /api/v1/sms/verify # 验证验证码 # 🔗 子资源嵌套(当前用户的资源) GET /api/v1/users/me/orders # 获取当前用户的订单 GET /api/v1/users/me/favorites # 获取当前用户的收藏 POST /api/v1/users/me/favorites # 添加收藏 DELETE /api/v1/users/me/favorites/:id # 删除收藏 # 🛍️ 跨域资源关系 GET /api/v1/orders/123 # 获取订单详情 GET /api/v1/orders/123/items # 获取订单商品 POST /api/v1/products/456/reviews # 为商品添加评论 # 🎯 特殊操作使用动词(在对应域内) PUT /api/v1/users/me/password # 修改密码 POST /api/v1/orders/123/cancel # 取消订单 POST /api/v1/payments/123/refund # 退款操作 ``` ### 2. DDD 多域 API 路径设计示例 ```bash # 👥 用户域 (User Domain) POST /api/v1/users/register # 用户注册 POST /api/v1/users/login # 用户登录 GET /api/v1/users/me # 获取当前用户 PUT /api/v1/users/me # 更新用户信息 PUT /api/v1/users/me/password # 修改密码 GET /api/v1/users/me/sessions # 获取登录会话 # 📦 订单域 (Order Domain) GET /api/v1/orders # 获取订单列表 POST /api/v1/orders # 创建订单 GET /api/v1/orders/:id # 获取订单详情 PUT /api/v1/orders/:id # 更新订单 POST /api/v1/orders/:id/cancel # 取消订单 GET /api/v1/orders/:id/items # 获取订单商品 # 🛍️ 商品域 (Product Domain) GET /api/v1/products # 获取商品列表 POST /api/v1/products # 创建商品 GET /api/v1/products/:id # 获取商品详情 PUT /api/v1/products/:id # 更新商品 GET /api/v1/products/:id/reviews # 获取商品评论 POST /api/v1/products/:id/reviews # 添加商品评论 # 💰 支付域 (Payment Domain) POST /api/v1/payments # 创建支付 GET /api/v1/payments/:id # 获取支付状态 POST /api/v1/payments/:id/refund # 申请退款 # 📱 通知域 (Notification Domain) GET /api/v1/notifications # 获取通知列表 PUT /api/v1/notifications/:id/read # 标记通知为已读 POST /api/v1/sms/send # 发送短信验证码 ``` ### 3. HTTP 状态码规范 ```bash # ✅ 成功响应 (2xx) 200 OK # 查询成功 (GET /api/v1/users/me) 201 Created # 创建成功 (POST /api/v1/users/register) 204 No Content # 删除成功 (DELETE /api/v1/users/me) # ❌ 客户端错误 (4xx) 400 Bad Request # 请求参数错误 401 Unauthorized # 未认证 (需要登录) 403 Forbidden # 无权限 (登录但权限不足) 404 Not Found # 资源不存在 422 Unprocessable Entity # 业务验证失败 429 Too Many Requests # 请求频率限制 # ⚠️ 服务器错误 (5xx) 500 Internal Server Error # 服务器内部错误 502 Bad Gateway # 网关错误 503 Service Unavailable # 服务不可用 ``` ### 4. 状态码在 DDD 架构中的应用 ```go // 用户域状态码示例 func (h *UserHandler) Login(c *gin.Context) { // 参数验证失败 if err := h.validator.BindAndValidate(c, &req); err != nil { // 422 Unprocessable Entity return } user, err := h.userService.Login(ctx, &req) if err != nil { switch { case errors.Is(err, domain.ErrUserNotFound): h.response.NotFound(c, "用户不存在") // 404 case errors.Is(err, domain.ErrInvalidPassword): h.response.Unauthorized(c, "密码错误") // 401 case errors.Is(err, domain.ErrUserBlocked): h.response.Forbidden(c, "账户已被禁用") // 403 default: h.response.InternalError(c, "登录失败") // 500 } return } h.response.Success(c, user, "登录成功") // 200 } func (h *UserHandler) Register(c *gin.Context) { user, err := h.userService.Register(ctx, &req) if err != nil { switch { case errors.Is(err, domain.ErrPhoneExists): h.response.Conflict(c, "手机号已存在") // 409 case errors.Is(err, domain.ErrInvalidCode): h.response.BadRequest(c, "验证码错误") // 400 default: h.response.InternalError(c, "注册失败") // 500 } return } h.response.Created(c, user, "注册成功") // 201 } ``` ## ✅ 数据验证规范 ### 1. 结构体标签验证 (中文提示) ```go // 用户注册请求验证 type RegisterRequest struct { Phone string `json:"phone" binding:"required,len=11" example:"13800138000"` Password string `json:"password" binding:"required,min=6,max=128" example:"password123"` ConfirmPassword string `json:"confirm_password" binding:"required,eqfield=Password" example:"password123"` Code string `json:"code" binding:"required,len=6" example:"123456"` } // 用户登录请求验证 type LoginWithPasswordRequest struct { Phone string `json:"phone" binding:"required,len=11" example:"13800138000"` Password string `json:"password" binding:"required" example:"password123"` } // 修改密码请求验证 type ChangePasswordRequest struct { OldPassword string `json:"old_password" binding:"required" example:"oldpassword123"` NewPassword string `json:"new_password" binding:"required,min=6,max=128" example:"newpassword123"` ConfirmNewPassword string `json:"confirm_new_password" binding:"required,eqfield=NewPassword" example:"newpassword123"` Code string `json:"code" binding:"required,len=6" example:"123456"` } ``` ### 2. 官方中文翻译包集成 项目集成了 `github.com/go-playground/validator/v10/translations/zh` 官方中文翻译包,自动提供专业的中文验证错误消息。 **集成优势:** - ✅ **官方支持**: 使用 validator 官方维护的中文翻译 - ✅ **专业翻译**: 所有标准验证规则都有准确的中文翻译 - ✅ **自动更新**: 跟随 validator 版本自动获得新功能的中文支持 - ✅ **智能结合**: 官方翻译 + 自定义字段名映射,提供最佳用户体验 - ✅ **兼容性好**: 保持与现有 API 接口的完全兼容 ```go // 创建支持中文翻译的验证器 func NewRequestValidatorZh(response interfaces.ResponseBuilder) interfaces.RequestValidator { // 创建验证器实例 validate := validator.New() // 创建中文locale zhLocale := zh.New() uni := ut.New(zhLocale, zhLocale) // 获取中文翻译器 trans, _ := uni.GetTranslator("zh") // 注册官方中文翻译 zh_translations.RegisterDefaultTranslations(validate, trans) // 注册自定义验证器和翻译 registerCustomValidatorsZh(validate, trans) return &RequestValidatorZh{ validator: validate, translator: trans, response: response, } } // 手机号验证器 func validatePhone(fl validator.FieldLevel) bool { phone := fl.Field().String() if phone == "" { return true // 空值由required标签处理 } // 中国手机号验证:11位,以1开头 matched, _ := regexp.MatchString(`^1[3-9]\d{9}$`, phone) return matched } // 用户名验证器 func validateUsername(fl validator.FieldLevel) bool { username := fl.Field().String() if username == "" { return true // 空值由required标签处理 } // 用户名规则:3-30字符,字母数字下划线,不能数字开头 if len(username) < 3 || len(username) > 30 { return false } matched, _ := regexp.MatchString(`^[a-zA-Z][a-zA-Z0-9_]*$`, username) return matched } // 强密码验证器 func validateStrongPassword(fl validator.FieldLevel) bool { password := fl.Field().String() if password == "" { return true // 空值由required标签处理 } // 密码强度:至少8位,包含大小写字母和数字 if len(password) < 8 { return false } hasUpper := regexp.MustCompile(`[A-Z]`).MatchString(password) hasLower := regexp.MustCompile(`[a-z]`).MatchString(password) hasDigit := regexp.MustCompile(`\d`).MatchString(password) return hasUpper && hasLower && hasDigit } ``` ### 3. 自定义验证器和翻译注册 ```go // 注册自定义验证器和中文翻译 func registerCustomValidatorsZh(v *validator.Validate, trans ut.Translator) { // 注册手机号验证器 v.RegisterValidation("phone", validatePhoneZh) v.RegisterTranslation("phone", trans, func(ut ut.Translator) error { return ut.Add("phone", "{0}必须是有效的手机号", true) }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T("phone", fe.Field()) return t }) // 注册用户名验证器 v.RegisterValidation("username", validateUsernameZh) v.RegisterTranslation("username", trans, func(ut ut.Translator) error { return ut.Add("username", "{0}格式不正确,只能包含字母、数字、下划线,且不能以数字开头", true) }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T("username", fe.Field()) return t }) // 注册密码强度验证器 v.RegisterValidation("strong_password", validateStrongPasswordZh) v.RegisterTranslation("strong_password", trans, func(ut ut.Translator) error { return ut.Add("strong_password", "{0}强度不足,必须包含大小写字母和数字,且不少于8位", true) }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T("strong_password", fe.Field()) return t }) } // 智能错误格式化(官方翻译 + 自定义字段名) func (v *RequestValidatorZh) formatValidationErrorsZh(err error) map[string][]string { errors := make(map[string][]string) if validationErrors, ok := err.(validator.ValidationErrors); ok { for _, fieldError := range validationErrors { fieldName := v.getFieldNameZh(fieldError) // 使用官方翻译器获取中文错误消息 errorMessage := fieldError.Translate(v.translator) // 替换字段名为中文显示名称 fieldDisplayName := v.getFieldDisplayName(fieldError.Field()) if fieldDisplayName != fieldError.Field() { errorMessage = strings.ReplaceAll(errorMessage, fieldError.Field(), fieldDisplayName) } if _, exists := errors[fieldName]; !exists { errors[fieldName] = []string{} } errors[fieldName] = append(errors[fieldName], errorMessage) } } return errors } ``` ### 4. 中文翻译效果对比 **标准验证规则** (官方翻译) ```json { "success": false, "message": "验证失败", "errors": { "phone": ["手机号必须是有效的手机号"], "email": ["email必须是一个有效的邮箱"], "password": ["password长度必须至少为8个字符"], "confirm_password": ["ConfirmPassword必须等于Password"], "age": ["age必须大于或等于18"] } } ``` **自定义验证规则** (自定义翻译) ```json { "success": false, "message": "验证失败", "errors": { "username": [ "用户名格式不正确,只能包含字母、数字、下划线,且不能以数字开头" ], "password": ["密码强度不足,必须包含大小写字母和数字,且不少于8位"] } } ``` **优化后的用户体验** 通过字段名映射,最终用户看到的是: ```json { "success": false, "message": "验证失败", "errors": { "phone": ["手机号必须是有效的手机号"], "email": ["邮箱必须是一个有效的邮箱"], "password": ["密码长度必须至少为8个字符"], "confirm_password": ["确认密码必须等于密码"], "age": ["年龄必须大于或等于18"] } } ``` ### 4. 验证器使用示例 ```go func (h *UserHandler) Register(c *gin.Context) { var req dto.RegisterRequest // 验证器会自动处理错误响应,返回中文错误信息 if err := h.validator.BindAndValidate(c, &req); err != nil { return // 验证失败,已返回带中文提示的错误响应 } // 继续业务逻辑... } // 验证失败时的响应示例 { "success": false, "message": "验证失败", "errors": { "phone": ["手机号 长度必须为 11 位"], "password": ["密码 长度不能少于 6 位"], "confirm_password": ["确认密码 必须与 密码 一致"], "code": ["验证码 长度必须为 6 位"] }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` ## 📊 分页和查询规范 ### 1. 分页参数 ```go type UserListRequest struct { Page int `form:"page" binding:"min=1"` PageSize int `form:"page_size" binding:"min=1,max=100"` Sort string `form:"sort"` // 排序字段 Order string `form:"order"` // asc/desc Search string `form:"search"` // 搜索关键词 Filters map[string]interface{} `form:"filters"` // 过滤条件 } ``` ### 2. 查询接口设计 ``` GET /api/v1/users?page=1&page_size=20&sort=created_at&order=desc&search=john ``` ## 🔧 中间件使用规范 ### 1. 全局中间件(按优先级) ```go // internal/container/container.go - RegisterMiddlewares router.RegisterMiddleware(requestID) // 95 - 请求ID router.RegisterMiddleware(security) // 85 - 安全头部 router.RegisterMiddleware(responseTime) // 75 - 响应时间 router.RegisterMiddleware(cors) // 70 - CORS router.RegisterMiddleware(rateLimit) // 65 - 限流 router.RegisterMiddleware(requestLogger) // 80 - 请求日志 ``` ### 2. 路由级中间件 ```go // 认证中间件 protected.Use(r.jwtAuth.Handle()) // 可选认证中间件 public.Use(r.optionalAuth.Handle()) // 自定义中间件 adminRoutes.Use(r.adminAuth.Handle()) ``` ## 🎯 错误处理规范 ### 1. 业务错误分类 (中文错误码和消息) ```go // 业务错误结构 type BusinessError struct { Code string `json:"code"` // 错误码 Message string `json:"message"` // 中文错误消息 Details interface{} `json:"details,omitempty"` // 错误详情 } // 用户域错误码定义 const ( // 用户相关错误 ErrUserNotFound = "USER_NOT_FOUND" // 用户不存在 ErrUserExists = "USER_EXISTS" // 用户已存在 ErrPhoneExists = "PHONE_EXISTS" // 手机号已存在 ErrInvalidCredentials = "INVALID_CREDENTIALS" // 登录凭据无效 ErrInvalidPassword = "INVALID_PASSWORD" // 密码错误 ErrUserBlocked = "USER_BLOCKED" // 用户被禁用 // 验证码相关错误 ErrInvalidCode = "INVALID_CODE" // 验证码错误 ErrCodeExpired = "CODE_EXPIRED" // 验证码已过期 ErrCodeUsed = "CODE_USED" // 验证码已使用 ErrCodeSendTooFrequent = "CODE_SEND_TOO_FREQUENT" // 验证码发送过于频繁 // 请求相关错误 ErrValidationFailed = "VALIDATION_FAILED" // 参数验证失败 ErrInvalidRequest = "INVALID_REQUEST" // 请求格式错误 ErrMissingParam = "MISSING_PARAM" // 缺少必需参数 // 权限相关错误 ErrUnauthorized = "UNAUTHORIZED" // 未认证 ErrForbidden = "FORBIDDEN" // 权限不足 ErrTokenExpired = "TOKEN_EXPIRED" // Token已过期 ErrTokenInvalid = "TOKEN_INVALID" // Token无效 // 系统相关错误 ErrInternalServer = "INTERNAL_SERVER_ERROR" // 服务器内部错误 ErrServiceUnavailable = "SERVICE_UNAVAILABLE" // 服务不可用 ErrRateLimitExceeded = "RATE_LIMIT_EXCEEDED" // 请求频率超限 ) // 错误消息映射(中文) var ErrorMessages = map[string]string{ // 用户相关 ErrUserNotFound: "用户不存在", ErrUserExists: "用户已存在", ErrPhoneExists: "手机号已被注册", ErrInvalidCredentials: "用户名或密码错误", ErrInvalidPassword: "密码错误", ErrUserBlocked: "账户已被禁用,请联系客服", // 验证码相关 ErrInvalidCode: "验证码错误", ErrCodeExpired: "验证码已过期,请重新获取", ErrCodeUsed: "验证码已使用,请重新获取", ErrCodeSendTooFrequent: "验证码发送过于频繁,请稍后再试", // 请求相关 ErrValidationFailed: "请求参数验证失败", ErrInvalidRequest: "请求格式错误", ErrMissingParam: "缺少必需参数", // 权限相关 ErrUnauthorized: "用户未登录或登录已过期", ErrForbidden: "权限不足,无法访问此资源", ErrTokenExpired: "登录已过期,请重新登录", ErrTokenInvalid: "登录信息无效,请重新登录", // 系统相关 ErrInternalServer: "服务器内部错误,请稍后重试", ErrServiceUnavailable: "服务暂时不可用,请稍后重试", ErrRateLimitExceeded: "请求过于频繁,请稍后再试", } // 创建业务错误 func NewBusinessError(code string, details ...interface{}) *BusinessError { message := ErrorMessages[code] if message == "" { message = "未知错误" } err := &BusinessError{ Code: code, Message: message, } if len(details) > 0 { err.Details = details[0] } return err } // 实现error接口 func (e *BusinessError) Error() string { return e.Message } ``` ### 2. 错误处理模式示例 ```go // 服务层错误处理 func (s *UserService) GetByID(ctx context.Context, id string) (*entities.User, error) { user, err := s.repo.GetByID(ctx, id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, NewBusinessError(ErrUserNotFound) } s.logger.Error("获取用户失败", zap.Error(err), zap.String("user_id", id)) return nil, NewBusinessError(ErrInternalServer) } return user, nil } func (s *UserService) Register(ctx context.Context, req *dto.RegisterRequest) (*entities.User, error) { // 检查手机号是否已存在 existingUser, err := s.repo.FindByPhone(ctx, req.Phone) if err == nil && existingUser != nil { return nil, NewBusinessError(ErrPhoneExists) } // 验证验证码 if err := s.smsCodeService.VerifyCode(ctx, req.Phone, req.Code, entities.SMSSceneRegister); err != nil { if strings.Contains(err.Error(), "expired") { return nil, NewBusinessError(ErrCodeExpired) } return nil, NewBusinessError(ErrInvalidCode) } // 创建用户... return user, nil } // Handler层错误处理 func (h *UserHandler) GetProfile(c *gin.Context) { userID := h.getCurrentUserID(c) if userID == "" { h.response.Unauthorized(c, ErrorMessages[ErrUnauthorized]) return } user, err := h.userService.GetByID(c.Request.Context(), userID) if err != nil { if bizErr, ok := err.(*BusinessError); ok { switch bizErr.Code { case ErrUserNotFound: h.response.NotFound(c, bizErr.Message) case ErrUnauthorized: h.response.Unauthorized(c, bizErr.Message) case ErrForbidden: h.response.Forbidden(c, bizErr.Message) default: h.response.InternalError(c, bizErr.Message) } } else { h.logger.Error("获取用户信息失败", zap.Error(err)) h.response.InternalError(c, ErrorMessages[ErrInternalServer]) } return } response := dto.FromEntity(user) h.response.Success(c, response, "获取用户信息成功") } // 登录错误处理示例 func (h *UserHandler) LoginWithPassword(c *gin.Context) { var req dto.LoginWithPasswordRequest if err := h.validator.BindAndValidate(c, &req); err != nil { return // 验证器已处理响应 } user, err := h.userService.LoginWithPassword(c.Request.Context(), &req) if err != nil { h.logger.Error("用户登录失败", zap.Error(err), zap.String("phone", req.Phone)) if bizErr, ok := err.(*BusinessError); ok { switch bizErr.Code { case ErrUserNotFound: h.response.NotFound(c, "手机号未注册") case ErrInvalidPassword: h.response.Unauthorized(c, "密码错误") case ErrUserBlocked: h.response.Forbidden(c, bizErr.Message) default: h.response.BadRequest(c, bizErr.Message) } } else { h.response.InternalError(c, "登录失败,请稍后重试") } return } // 生成JWT token... h.response.Success(c, loginResponse, "登录成功") } ``` ### 3. 统一错误响应格式 ```go // 错误响应中间件 func ErrorHandlerMiddleware() gin.HandlerFunc { return func(c *gin.Context) { c.Next() // 检查是否有未处理的错误 if len(c.Errors) > 0 { err := c.Errors.Last().Err if bizErr, ok := err.(*BusinessError); ok { // 业务错误 c.JSON(getHTTPStatus(bizErr.Code), gin.H{ "success": false, "message": bizErr.Message, "error_code": bizErr.Code, "details": bizErr.Details, "request_id": c.GetString("request_id"), "timestamp": time.Now().Unix(), }) } else { // 系统错误 c.JSON(500, gin.H{ "success": false, "message": ErrorMessages[ErrInternalServer], "error_code": ErrInternalServer, "request_id": c.GetString("request_id"), "timestamp": time.Now().Unix(), }) } } } } // 根据错误码获取HTTP状态码 func getHTTPStatus(errorCode string) int { statusMap := map[string]int{ ErrValidationFailed: 400, // Bad Request ErrInvalidRequest: 400, ErrMissingParam: 400, ErrInvalidCode: 400, ErrPhoneExists: 409, // Conflict ErrUserExists: 409, ErrUnauthorized: 401, // Unauthorized ErrTokenExpired: 401, ErrTokenInvalid: 401, ErrInvalidCredentials: 401, ErrForbidden: 403, // Forbidden ErrUserBlocked: 403, ErrUserNotFound: 404, // Not Found ErrCodeSendTooFrequent: 429, // Too Many Requests ErrRateLimitExceeded: 429, ErrInternalServer: 500, // Internal Server Error ErrServiceUnavailable: 503, // Service Unavailable } if status, exists := statusMap[errorCode]; exists { return status } return 500 // 默认服务器错误 } ``` ## 📈 日志记录规范 ### 1. 结构化日志 (中文日志消息) ```go // 成功日志 h.logger.Info("用户注册成功", zap.String("user_id", user.ID), zap.String("phone", user.Phone), zap.String("request_id", c.GetString("request_id"))) h.logger.Info("用户登录成功", zap.String("user_id", user.ID), zap.String("phone", user.Phone), zap.String("login_method", "password"), zap.String("ip_address", c.ClientIP()), zap.String("request_id", c.GetString("request_id"))) h.logger.Info("验证码发送成功", zap.String("phone", req.Phone), zap.String("scene", string(req.Scene)), zap.String("request_id", c.GetString("request_id"))) // 错误日志 h.logger.Error("用户注册失败", zap.Error(err), zap.String("phone", req.Phone), zap.String("error_type", "business_logic"), zap.String("request_id", c.GetString("request_id"))) h.logger.Error("数据库操作失败", zap.Error(err), zap.String("operation", "create_user"), zap.String("table", "users"), zap.String("request_id", c.GetString("request_id"))) h.logger.Error("外部服务调用失败", zap.Error(err), zap.String("service", "sms_service"), zap.String("action", "send_code"), zap.String("phone", req.Phone), zap.String("request_id", c.GetString("request_id"))) // 警告日志 h.logger.Warn("验证码重复发送", zap.String("phone", req.Phone), zap.String("scene", string(req.Scene)), zap.Int("retry_count", retryCount), zap.String("request_id", c.GetString("request_id"))) h.logger.Warn("异常登录尝试", zap.String("phone", req.Phone), zap.String("ip_address", c.ClientIP()), zap.String("user_agent", c.GetHeader("User-Agent")), zap.Int("attempt_count", attemptCount), zap.String("request_id", c.GetString("request_id"))) // 调试日志 h.logger.Debug("开始处理用户注册请求", zap.String("phone", req.Phone), zap.String("request_id", c.GetString("request_id"))) ``` ### 2. 日志级别使用规范 - **Debug**: 详细的调试信息(开发环境) - 请求参数详情 - 中间步骤状态 - 性能指标数据 - **Info**: 重要的业务信息(生产环境) - 用户操作成功记录 - 系统状态变更 - 业务流程关键节点 - **Warn**: 需要关注但不影响主功能的问题 - 重试操作 - 降级处理 - 资源使用超预期 - **Error**: 影响功能的错误信息 - 业务逻辑错误 - 数据库操作失败 - 外部服务调用失败 ### 3. 日志上下文信息规范 ```go // 必需字段 - request_id: 请求追踪ID - user_id: 用户ID(如果已认证) - action: 操作类型 - timestamp: 时间戳(自动添加) // 可选字段 - phone: 手机号(敏感信息需脱敏) - ip_address: 客户端IP - user_agent: 用户代理 - error_type: 错误类型分类 - duration: 操作耗时 - service: 服务名称 - method: 请求方法 - path: 请求路径 // 脱敏处理示例 func maskPhone(phone string) string { if len(phone) != 11 { return phone } return phone[:3] + "****" + phone[7:] } h.logger.Info("用户登录成功", zap.String("phone", maskPhone(user.Phone)), // 138****8000 zap.String("user_id", user.ID), zap.String("request_id", c.GetString("request_id"))) ``` ## 🧪 测试规范 ### 1. 单元测试 ```go func TestUserService_Create(t *testing.T) { // 使用testify进行测试 assert := assert.New(t) // Mock依赖 mockRepo := &mocks.UserRepository{} mockEventBus := &mocks.EventBus{} service := services.NewUserService(mockRepo, mockEventBus, logger) // 测试用例... user, err := service.Create(ctx, req) assert.NoError(err) assert.NotNil(user) } ``` ### 2. 集成测试 ```go func TestUserHandler_Create(t *testing.T) { // 设置测试环境 router := setupTestRouter() // 发送测试请求 w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/api/v1/users", bytes.NewBuffer(jsonData)) router.ServeHTTP(w, req) // 验证响应 assert.Equal(t, 201, w.Code) } ``` ## 🚀 新增业务领域开发指南 ### 1. 创建新领域 ```bash # 1. 创建领域目录结构 mkdir -p internal/domains/product/{dto,entities,events,handlers,repositories,routes,services,validators} # 2. 复制用户领域作为模板 cp -r internal/domains/user/* internal/domains/product/ # 3. 修改包名和结构体名称 ``` ### 2. 注册到依赖注入容器 ```go // internal/container/container.go fx.Provide( // Product domain NewProductRepository, NewProductService, NewProductHandler, NewProductRoutes, ), fx.Invoke( RegisterProductRoutes, ), ``` ### 3. 添加路由注册 ```go func RegisterProductRoutes( router *http.GinRouter, productRoutes *routes.ProductRoutes, ) { productRoutes.RegisterRoutes(router.GetEngine()) productRoutes.RegisterPublicRoutes(router.GetEngine()) productRoutes.RegisterAdminRoutes(router.GetEngine()) } ``` ## 🚀 DDD 新域开发指南 ### 1. 创建新业务域 ```bash # 1. 创建领域目录结构(以订单域为例) mkdir -p internal/domains/order/{dto,entities,events,handlers,repositories,routes,services} # 2. 复制用户域作为模板 cp -r internal/domains/user/* internal/domains/order/ # 3. 批量替换包名和结构体名称 ``` ### 2. 定义领域实体和 DTO ```go // internal/domains/order/entities/order.go type Order struct { ID string `json:"id" gorm:"primaryKey"` UserID string `json:"user_id" gorm:"not null"` TotalAmount float64 `json:"total_amount"` Status Status `json:"status"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // internal/domains/order/dto/order_dto.go type CreateOrderRequest struct { Items []OrderItem `json:"items" binding:"required,dive"` } type OrderResponse struct { ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"` UserID string `json:"user_id" example:"user-123"` TotalAmount float64 `json:"total_amount" example:"99.99"` Status string `json:"status" example:"pending"` CreatedAt time.Time `json:"created_at" example:"2024-01-01T00:00:00Z"` } ``` ### 3. 配置领域路由 ```go // internal/domains/order/routes/order_routes.go func (r *OrderRoutes) RegisterRoutes(router *gin.Engine) { v1 := router.Group("/api/v1") // 📦 订单域路由组 orders := v1.Group("/orders") { // 公开查询(可选认证) orders.GET("/:id/public", r.handler.GetPublicOrder) // 需要认证的路由 authenticated := orders.Group("") authenticated.Use(r.jwtAuth.Handle()) { authenticated.GET("", r.handler.List) // GET /api/v1/orders authenticated.POST("", r.handler.Create) // POST /api/v1/orders authenticated.GET("/:id", r.handler.GetByID) // GET /api/v1/orders/:id authenticated.PUT("/:id", r.handler.Update) // PUT /api/v1/orders/:id authenticated.POST("/:id/cancel", r.handler.Cancel) // POST /api/v1/orders/:id/cancel authenticated.GET("/:id/items", r.handler.GetItems) // GET /api/v1/orders/:id/items } } } ``` ### 4. 注册到依赖注入容器 ```go // internal/container/container.go fx.Provide( // User domain repositories.NewUserRepository, services.NewUserService, handlers.NewUserHandler, routes.NewUserRoutes, // Order domain - 新增 order_repositories.NewOrderRepository, order_services.NewOrderService, order_handlers.NewOrderHandler, order_routes.NewOrderRoutes, ), fx.Invoke( RegisterUserRoutes, RegisterOrderRoutes, // 新增 ), // 添加路由注册函数 func RegisterOrderRoutes( router *http.GinRouter, orderRoutes *order_routes.OrderRoutes, ) { orderRoutes.RegisterRoutes(router.GetEngine()) } ``` ### 5. 跨域关系处理 ```go // 用户订单关系 - 在用户域添加 func (r *UserRoutes) RegisterRoutes(router *gin.Engine) { users := v1.Group("/users") authenticated := users.Group("") authenticated.Use(r.jwtAuth.Handle()) { authenticated.GET("/me", r.handler.GetProfile) // 添加用户相关的订单操作 authenticated.GET("/me/orders", r.handler.GetUserOrders) // 获取用户订单 authenticated.GET("/me/orders/stats", r.handler.GetOrderStats) // 订单统计 } } // 或者在订单域处理用户关系 func (h *OrderHandler) List(c *gin.Context) { userID := h.getCurrentUserID(c) // 从JWT中获取用户ID orders, err := h.orderService.GetUserOrders(ctx, userID) // ... 业务逻辑 } ``` ## 📖 Swagger/OpenAPI 文档集成指南 ### 1. 新增接口 Swagger 文档支持 #### 为 Handler 方法添加 Swagger 注释 ```go // @Summary 接口简短描述(必需) // @Description 接口详细描述(可选) // @Tags 标签分组(推荐) // @Accept json // @Produce json // @Security Bearer # 如果需要JWT认证 // @Param request body dto.RequestStruct true "请求参数描述" // @Param id path string true "路径参数描述" // @Param page query int false "查询参数描述" // @Success 200 {object} dto.ResponseStruct "成功响应描述" // @Failure 400 {object} map[string]interface{} "错误响应描述" // @Router /api/v1/your-endpoint [post] func (h *YourHandler) YourMethod(c *gin.Context) { // Handler实现 } ``` #### Swagger 注释语法详解 ```go // 基础注释 // @Summary 接口摘要(在文档列表中显示) // @Description 详细描述(支持多行) // @Tags 标签分组(用于在UI中分组显示) // 请求/响应格式 // @Accept 接受的内容类型:json, xml, plain, html, mpfd, x-www-form-urlencoded // @Produce 响应的内容类型:json, xml, plain, html // 安全认证 // @Security Bearer # JWT认证 // @Security ApiKeyAuth # API Key认证 // @Security BasicAuth # 基础认证 // 参数定义 // @Param name location type required "description" Enums(A,B,C) default(A) // location: query, path, header, body, formData // type: string, number, integer, boolean, array, object // required: true, false // 响应定义 // @Success code {type} model "description" // @Failure code {type} model "description" // code: HTTP状态码 // type: object, array, string, number, boolean // model: 响应模型(如dto.UserResponse) // 路由定义 // @Router path [method] // method: get, post, put, delete, patch, head, options ``` ### 2. 完整示例:订单域接口文档 ```go // CreateOrder 创建订单 // @Summary 创建新订单 // @Description 根据购物车内容创建新的订单,支持多商品下单 // @Tags 订单管理 // @Accept json // @Produce json // @Security Bearer // @Param request body dto.CreateOrderRequest true "创建订单请求" // @Success 201 {object} dto.OrderResponse "订单创建成功" // @Failure 400 {object} map[string]interface{} "请求参数错误" // @Failure 401 {object} map[string]interface{} "未认证" // @Failure 422 {object} map[string]interface{} "业务验证失败" // @Failure 500 {object} map[string]interface{} "服务器内部错误" // @Router /api/v1/orders [post] func (h *OrderHandler) CreateOrder(c *gin.Context) { // 实现代码 } // GetOrderList 获取订单列表 // @Summary 获取当前用户的订单列表 // @Description 分页获取当前用户的订单列表,支持按状态筛选和关键词搜索 // @Tags 订单管理 // @Accept json // @Produce json // @Security Bearer // @Param page query int false "页码" default(1) minimum(1) // @Param page_size query int false "每页数量" default(20) minimum(1) maximum(100) // @Param status query string false "订单状态" Enums(pending,paid,shipped,delivered,cancelled) // @Param search query string false "搜索关键词" // @Success 200 {object} dto.OrderListResponse "订单列表" // @Failure 400 {object} map[string]interface{} "请求参数错误" // @Failure 401 {object} map[string]interface{} "未认证" // @Failure 500 {object} map[string]interface{} "服务器内部错误" // @Router /api/v1/orders [get] func (h *OrderHandler) GetOrderList(c *gin.Context) { // 实现代码 } // UpdateOrder 更新订单 // @Summary 更新订单信息 // @Description 更新指定订单的部分信息,如收货地址、备注等 // @Tags 订单管理 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "订单ID" Format(uuid) // @Param request body dto.UpdateOrderRequest true "更新订单请求" // @Success 200 {object} dto.OrderResponse "订单更新成功" // @Failure 400 {object} map[string]interface{} "请求参数错误" // @Failure 401 {object} map[string]interface{} "未认证" // @Failure 403 {object} map[string]interface{} "无权限操作此订单" // @Failure 404 {object} map[string]interface{} "订单不存在" // @Failure 500 {object} map[string]interface{} "服务器内部错误" // @Router /api/v1/orders/{id} [put] func (h *OrderHandler) UpdateOrder(c *gin.Context) { // 实现代码 } ``` ### 3. DTO 结构体文档化 #### 为请求/响应结构体添加文档标签 ```go // CreateOrderRequest 创建订单请求 type CreateOrderRequest struct { Items []OrderItem `json:"items" binding:"required,dive" example:"[{\"product_id\":\"123\",\"quantity\":2}]"` DeliveryAddress string `json:"delivery_address" binding:"required,max=200" example:"北京市朝阳区xxx街道xxx号"` PaymentMethod string `json:"payment_method" binding:"required,oneof=alipay wechat" example:"alipay"` Remark string `json:"remark" binding:"max=500" example:"请尽快发货"` } // @name CreateOrderRequest // OrderResponse 订单响应 type OrderResponse struct { ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"` UserID string `json:"user_id" example:"user-123"` OrderNo string `json:"order_no" example:"ORD20240101001"` Status OrderStatus `json:"status" example:"pending"` TotalAmount float64 `json:"total_amount" example:"299.99"` PaymentMethod string `json:"payment_method" example:"alipay"` DeliveryAddress string `json:"delivery_address" example:"北京市朝阳区xxx街道xxx号"` Items []OrderItem `json:"items"` CreatedAt time.Time `json:"created_at" example:"2024-01-01T00:00:00Z"` UpdatedAt time.Time `json:"updated_at" example:"2024-01-01T00:00:00Z"` } // @name OrderResponse // OrderItem 订单商品项 type OrderItem struct { ProductID string `json:"product_id" example:"prod-123"` ProductName string `json:"product_name" example:"iPhone 15 Pro"` Quantity int `json:"quantity" example:"1"` Price float64 `json:"price" example:"999.99"` Subtotal float64 `json:"subtotal" example:"999.99"` } // @name OrderItem // OrderListResponse 订单列表响应 type OrderListResponse struct { Orders []OrderResponse `json:"orders"` Pagination Pagination `json:"pagination"` } // @name OrderListResponse // Pagination 分页信息 type Pagination struct { Page int `json:"page" example:"1"` PageSize int `json:"page_size" example:"20"` Total int `json:"total" example:"150"` TotalPages int `json:"total_pages" example:"8"` } // @name Pagination ``` #### 枚举类型文档化 ```go // OrderStatus 订单状态 type OrderStatus string const ( OrderStatusPending OrderStatus = "pending" // 待支付 OrderStatusPaid OrderStatus = "paid" // 已支付 OrderStatusShipped OrderStatus = "shipped" // 已发货 OrderStatusDelivered OrderStatus = "delivered" // 已送达 OrderStatusCancelled OrderStatus = "cancelled" // 已取消 ) // 为枚举添加Swagger文档 // @Description 订单状态 // @Enum pending,paid,shipped,delivered,cancelled ``` ### 4. 文档生成和更新流程 #### 标准工作流程 ```bash # 1. 编写/修改Handler方法,添加Swagger注释 vim internal/domains/order/handlers/order_handler.go # 2. 编写/修改DTO结构体,添加example标签 vim internal/domains/order/dto/order_dto.go # 3. 重新生成Swagger文档 make docs # 或直接使用命令 swag init -g cmd/api/main.go -o docs/swagger # 4. 重启项目 go run cmd/api/main.go # 5. 访问文档查看效果 open http://localhost:8080/swagger/index.html ``` #### 快速开发脚本 ```bash # 创建docs脚本:scripts/update-docs.sh #!/bin/bash echo "🔄 Updating Swagger documentation..." # 生成文档 make docs if [ $? -eq 0 ]; then echo "✅ Swagger documentation updated successfully!" echo "📖 View at: http://localhost:8080/swagger/index.html" else echo "❌ Failed to update documentation" exit 1 fi # 重启开发服务器(可选) if [ "$1" = "--restart" ]; then echo "🔄 Restarting development server..." pkill -f "go run cmd/api/main.go" nohup go run cmd/api/main.go > /dev/null 2>&1 & echo "🚀 Development server restarted!" fi ``` ### 5. 文档质量检查清单 #### 必需元素检查 - [ ] **@Summary**: 简洁明了的接口描述 - [ ] **@Description**: 详细的功能说明 - [ ] **@Tags**: 正确的分组标签 - [ ] **@Router**: 正确的路径和 HTTP 方法 - [ ] **@Accept/@Produce**: 正确的内容类型 - [ ] **@Security**: 认证要求(如需要) #### 参数文档检查 - [ ] **路径参数**: 所有{id}等路径参数都有@Param - [ ] **查询参数**: 分页、筛选等参数都有@Param - [ ] **请求体**: 复杂请求有@Param body 定义 - [ ] **示例值**: 所有参数都有 realistic 的 example #### 响应文档检查 - [ ] **成功响应**: @Success 定义了正确的状态码和模型 - [ ] **错误响应**: @Failure 覆盖了主要的错误场景 - [ ] **响应模型**: DTO 结构体有完整的 json 标签和 example - [ ] **状态码**: 符合 RESTful 规范 ### 6. 高级文档特性 #### 自定义响应模型 ```go // 为复杂响应创建专门的文档模型 type APIResponse struct { Success bool `json:"success" example:"true"` Data interface{} `json:"data"` Message string `json:"message" example:"操作成功"` RequestID string `json:"request_id" example:"req-123"` Timestamp int64 `json:"timestamp" example:"1640995200"` } // @name APIResponse // 在Handler中使用 // @Success 200 {object} APIResponse{data=dto.OrderResponse} "成功响应" ``` #### 分组和版本管理 ```go // 使用一致的标签分组 // @Tags 用户认证 # 认证相关接口 // @Tags 用户管理 # 用户CRUD接口 // @Tags 订单管理 # 订单相关接口 // @Tags 商品管理 # 商品相关接口 // @Tags 系统管理 # 系统功能接口 // 版本控制 // @Router /api/v1/users [post] # V1版本 // @Router /api/v2/users [post] # V2版本(向后兼容) ``` ### 7. 常见问题和解决方案 #### 问题 1:文档生成失败 ```bash # 检查Swagger注释语法 swag init -g cmd/api/main.go -o docs/swagger --parseDependency # 常见错误: # - 缺少@Router注释 # - HTTP方法写错(必须小写) # - 路径格式不正确 # - 缺少必需的包导入 ``` #### 问题 2:模型没有正确显示 ```bash # 确保结构体有正确的标签 type UserRequest struct { Name string `json:"name" example:"张三"` # json标签必需 } // @name UserRequest # 显式命名(可选) # 确保包被正确解析 swag init -g cmd/api/main.go -o docs/swagger --parseDependency --parseInternal ``` #### 问题 3:认证测试失败 ```go // 确保安全定义正确 // @securityDefinitions.apikey Bearer // @in header // @name Authorization // @description Type "Bearer" followed by a space and JWT token. // 在接口中正确使用 // @Security Bearer ``` ### 8. 持续集成中的文档检查 ```bash # CI脚本示例:.github/workflows/docs.yml name: API Documentation Check on: [push, pull_request] jobs: docs-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Go uses: actions/setup-go@v2 with: go-version: 1.23 - name: Install swag run: go install github.com/swaggo/swag/cmd/swag@latest - name: Generate docs run: make docs - name: Check docs are up to date run: | if [[ `git status --porcelain docs/` ]]; then echo "Documentation is out of date. Please run 'make docs'" exit 1 fi ``` ## 📚 最佳实践总结 ### 🏗️ 架构设计原则 1. **领域驱动设计**: 按业务域组织代码和 API 路径,避免技术导向设计 2. **单一职责原则**: 每个层只负责自己的职责,保持清晰的边界分离 3. **依赖注入管理**: 使用 Uber FX 进行依赖管理,支持模块化扩展 4. **接口隔离原则**: 定义清晰的接口边界,便于测试和扩展 ### 📋 API 设计规范 5. **统一响应格式**: 标准化的 API 响应结构和中文错误提示 6. **RESTful 路径设计**: 语义化路径清晰表达业务意图 7. **多层数据验证**: 从 DTO 到业务规则的完整验证链 8. **中文化用户体验**: 所有面向用户的消息都使用中文 ### 🔧 技术实现规范 9. **结构化日志记录**: 使用 Zap 记录中文结构化日志,便于监控和调试 10. **智能缓存策略**: 合理使用 Redis 缓存提升系统性能 11. **事件驱动架构**: 使用领域事件解耦业务逻辑,支持异步处理 12. **错误处理分层**: 统一的业务错误码和 HTTP 状态码映射 ### 📖 开发协作规范 13. **文档优先开发**: 编写接口时同步维护 Swagger 文档,确保文档和代码一致性 14. **完整测试覆盖**: 单元测试、集成测试和端到端测试 15. **代码审查机制**: 确保代码质量和规范一致性 16. **持续集成部署**: 自动化构建、测试和部署流程 ### 🚀 性能和扩展性 17. **数据库事务管理**: 合理使用数据库事务确保数据一致性 18. **请求限流保护**: 防止恶意请求和系统过载 19. **监控和告警**: 完整的应用性能监控和业务指标收集 20. **水平扩展支持**: 微服务架构支持横向扩展 ## 🔄 配置管理 ### 1. 环境配置 ```yaml # config.yaml (开发环境) server: port: "8080" mode: "debug" # config.prod.yaml (生产环境) server: port: "8080" mode: "release" ``` ### 2. 环境变量覆盖 ```bash # 优先级: 环境变量 > 配置文件 > 默认值 export ENV=production export DB_HOST=prod-database export JWT_SECRET=secure-jwt-secret ``` ## 📋 当前项目 API 接口清单 ### 👥 用户域 (User Domain) ```bash # 🌍 公开接口(无需认证) POST /api/v1/users/send-code # 发送验证码 POST /api/v1/users/register # 用户注册 POST /api/v1/users/login # 用户登录 # 🔐 认证接口(需要JWT Token) GET /api/v1/users/me # 获取当前用户信息 PUT /api/v1/users/me/password # 修改密码 ``` ### 📱 SMS 验证码域 ```bash # 🌍 公开接口 POST /api/v1/sms/send # 发送验证码(与users/send-code相同) ``` ### 🔧 系统接口 ```bash # 🌍 健康检查 GET /health # 系统健康状态 GET /health/detailed # 详细健康状态 ``` ### 📊 请求示例 #### 发送验证码 ```bash curl -X POST http://localhost:8080/api/v1/users/send-code \ -H "Content-Type: application/json" \ -d '{ "phone": "13800138000", "scene": "register" }' # 响应示例 { "success": true, "message": "验证码发送成功", "data": { "message": "验证码已发送到您的手机", "expires_at": "2024-01-01T00:05:00Z" }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` #### 用户注册 ```bash curl -X POST http://localhost:8080/api/v1/users/register \ -H "Content-Type: application/json" \ -d '{ "phone": "13800138000", "password": "password123", "confirm_password": "password123", "code": "123456" }' # 响应示例 { "success": true, "message": "用户注册成功", "data": { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` #### 密码登录 ```bash curl -X POST http://localhost:8080/api/v1/users/login-password \ -H "Content-Type: application/json" \ -d '{ "phone": "13800138000", "password": "password123" }' # 响应示例 { "success": true, "message": "登录成功", "data": { "user": { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 86400, "login_method": "password" }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` #### 短信验证码登录 ```bash curl -X POST http://localhost:8080/api/v1/users/login-sms \ -H "Content-Type: application/json" \ -d '{ "phone": "13800138000", "code": "123456" }' # 响应示例同密码登录,login_method为"sms" ``` #### 获取当前用户信息 ```bash curl -X GET http://localhost:8080/api/v1/users/me \ -H "Authorization: Bearer " # 响应示例 { "success": true, "message": "获取用户信息成功", "data": { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` #### 修改密码 ```bash curl -X PUT http://localhost:8080/api/v1/users/me/password \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "old_password": "oldpassword123", "new_password": "newpassword123", "confirm_new_password": "newpassword123", "code": "123456" }' # 响应示例 { "success": true, "message": "密码修改成功", "data": null, "request_id": "req_123456789", "timestamp": 1704067200 } ``` #### 错误响应示例 ```bash # 参数验证失败 { "success": false, "message": "请求参数验证失败", "errors": { "phone": ["手机号 长度必须为 11 位"], "password": ["密码 长度不能少于 6 位"] }, "request_id": "req_123456789", "timestamp": 1704067200 } # 业务逻辑错误 { "success": false, "message": "手机号已被注册", "request_id": "req_123456789", "timestamp": 1704067200 } # 认证失败 { "success": false, "message": "用户未登录或登录已过期", "request_id": "req_123456789", "timestamp": 1704067200 } ``` ### 🔄 响应格式示例 #### 成功响应 ```json // 用户注册成功 { "success": true, "message": "用户注册成功", "data": { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, "request_id": "req_123456789", "timestamp": 1704067200 } // 用户登录成功 { "success": true, "message": "登录成功", "data": { "user": { "id": "123e4567-e89b-12d3-a456-426614174000", "phone": "13800138000", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 86400, "login_method": "password" }, "request_id": "req_123456789", "timestamp": 1704067200 } // 发送验证码成功 { "success": true, "message": "验证码发送成功", "data": { "message": "验证码已发送", "expires_at": "2024-01-01T00:05:00Z" }, "request_id": "req_123456789", "timestamp": 1704067200 } ``` #### 错误响应 ```json // 参数验证失败 { "success": false, "message": "请求参数验证失败", "errors": { "phone": ["手机号 长度必须为 11 位"], "password": ["密码 长度不能少于 6 位"], "code": ["验证码 长度必须为 6 位"] }, "request_id": "req_123456789", "timestamp": 1704067200 } // 业务逻辑错误 { "success": false, "message": "手机号已被注册", "request_id": "req_123456789", "timestamp": 1704067200 } // 认证失败 { "success": false, "message": "用户未登录或登录已过期", "request_id": "req_123456789", "timestamp": 1704067200 } // 验证码错误 { "success": false, "message": "验证码错误或已过期", "request_id": "req_123456789", "timestamp": 1704067200 } ``` --- 遵循以上规范,可以确保 API 开发的一致性、可维护性和扩展性。 # TYAPI Server 企业级高级特性完整集成指南 ## 🚀 **高级特性完整解决方案实施完成** 本项目现已成功集成所有企业级高级特性,提供完整的可观测性、弹性恢复和分布式事务能力。所有组件均已通过编译验证和容器集成。 ## 📊 **已完整集成的高级特性** ### 1. **🔍 分布式链路追踪 (Distributed Tracing)** **技术栈**: OpenTelemetry + OTLP 导出器 **支持后端**: Jaeger、Zipkin、Tempo、任何 OTLP 兼容系统 **状态**: ✅ **完全集成** ```yaml # 配置示例 (config.yaml) monitoring: tracing_enabled: true tracing_endpoint: "http://localhost:4317" # OTLP gRPC endpoint sample_rate: 0.1 ``` **核心特性**: - ✅ HTTP 请求自动追踪中间件 - ✅ 数据库操作追踪 - ✅ 缓存操作追踪 - ✅ 自定义业务操作追踪 - ✅ TraceID/SpanID 自动传播 - ✅ 生产级批处理导出 - ✅ 容器生命周期管理 **使用示例**: ```go // 自动HTTP追踪(已在所有路由启用) // 每个HTTP请求都会创建完整的追踪链路 // 自定义业务操作追踪 ctx, span := tracer.StartSpan(ctx, "business.user_registration") defer span.End() // 数据库操作追踪 ctx, span := tracer.StartDBSpan(ctx, "SELECT", "users", "WHERE phone = ?") defer span.End() // 缓存操作追踪 ctx, span := tracer.StartCacheSpan(ctx, "GET", "user:cache:123") defer span.End() ``` ### 2. **📈 指标监控 (Metrics Collection)** **技术栈**: Prometheus + 自定义业务指标 **导出端点**: `/metrics` (Prometheus 格式) **状态**: ✅ **完全集成** **自动收集指标**: ``` # HTTP请求指标 http_requests_total{method="GET",path="/api/v1/users",status="200"} 1523 http_request_duration_seconds{method="GET",path="/api/v1/users"} 0.045 # 业务指标 business_user_created_total{source="register"} 245 business_user_login_total{platform="web",status="success"} 1892 business_sms_sent_total{type="verification",provider="aliyun"} 456 # 系统指标 active_users_total 1024 database_connections_active 12 cache_operations_total{operation="get",result="hit"} 8745 ``` **自定义指标注册**: ```go // 注册自定义计数器 metrics.RegisterCounter("custom_events_total", "Custom events counter", []string{"event_type", "source"}) // 记录指标 metrics.IncrementCounter("custom_events_total", map[string]string{ "event_type": "user_action", "source": "web", }) ``` ### 3. **🛡️ 弹性恢复 (Resilience)** #### 3.1 **熔断器 (Circuit Breaker)** **状态**: ✅ **完全集成** ```go // 使用熔断器保护服务调用 err := circuitBreaker.Execute("user-service", func() error { return userService.GetUserByID(ctx, userID) }) // 批量执行保护 err := circuitBreaker.ExecuteBatch("batch-operation", []func() error{ func() error { return service1.Call() }, func() error { return service2.Call() }, }) ``` **特性**: - ✅ 故障阈值自动检测 - ✅ 半开状态自动恢复 - ✅ 实时状态监控 - ✅ 多种失败策略 #### 3.2 **重试机制 (Retry)** **状态**: ✅ **完全集成** ```go // 快速重试(适用于网络抖动) err := retryer.ExecuteWithQuickRetry(ctx, "api-call", func() error { return httpClient.Call() }) // 标准重试(适用于业务操作) err := retryer.ExecuteWithStandardRetry(ctx, "db-operation", func() error { return db.Save(data) }) // 耐心重试(适用于最终一致性) err := retryer.ExecuteWithPatientRetry(ctx, "sync-operation", func() error { return syncService.Sync() }) ``` ### 4. **🔄 分布式事务 (Saga Pattern)** **状态**: ✅ **完全集成** ```go // 创建分布式事务 saga := sagaManager.CreateSaga("user-registration-001", "用户注册流程") // 添加事务步骤 saga.AddStep("create-user", // 正向操作 func(ctx context.Context, data interface{}) error { return userService.CreateUser(ctx, data) }, // 补偿操作 func(ctx context.Context, data interface{}) error { return userService.DeleteUser(ctx, data) }) saga.AddStep("send-welcome-email", func(ctx context.Context, data interface{}) error { return emailService.SendWelcome(ctx, data) }, func(ctx context.Context, data interface{}) error { return emailService.SendCancellation(ctx, data) }) // 执行事务 err := saga.Execute(ctx, userData) ``` **支持特性**: - ✅ 自动补偿机制 - ✅ 步骤重试策略 - ✅ 事务状态跟踪 - ✅ 并发控制 ### 5. **🪝 事件钩子系统 (Hook System)** **状态**: ✅ **完全集成** ```go // 注册业务事件钩子 hookSystem.OnUserCreated("metrics-collector", hooks.PriorityHigh, func(ctx context.Context, user interface{}) error { return businessMetrics.RecordUserCreated("register") }) hookSystem.OnUserCreated("welcome-email", hooks.PriorityNormal, func(ctx context.Context, user interface{}) error { return emailService.SendWelcome(ctx, user) }) // 触发事件(在业务代码中) results, err := hookSystem.TriggerUserCreated(ctx, newUser) ``` **钩子类型**: - ✅ 同步钩子(阻塞执行) - ✅ 异步钩子(后台执行) - ✅ 优先级控制 - ✅ 超时保护 - ✅ 错误策略(继续/停止/收集) ## 🏗️ **架构集成图** ``` ┌─────────────────────────────────────────────────────────────┐ │ HTTP 请求层 │ ├─────────────────────────────────────────────────────────────┤ │ 追踪中间件 → 指标中间件 → 限流中间件 → 认证中间件 │ ├─────────────────────────────────────────────────────────────┤ │ 业务处理层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Handler │ │ Service │ │ Repository │ │ │ │ + 钩子 │ │ + 重试 │ │ + 熔断器 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ 基础设施层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 链路追踪 │ │ 指标收集 │ │ 分布式事务 │ │ │ │ (OpenTel) │ │(Prometheus) │ │ (Saga) │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## 🛠️ **使用指南** ### **启动验证** 1. **编译验证**: ```bash go build ./cmd/api ``` 2. **启动应用**: ```bash ./api ``` 3. **检查指标端点**: ```bash curl http://localhost:8080/metrics ``` 4. **检查健康状态**: ```bash curl http://localhost:8080/health ``` ### **配置示例** ```yaml # config.yaml 完整高级特性配置 app: name: "tyapi-server" version: "1.0.0" env: "production" monitoring: # 链路追踪配置 tracing_enabled: true tracing_endpoint: "http://jaeger:4317" sample_rate: 0.1 # 指标收集配置 metrics_enabled: true metrics_endpoint: "/metrics" resilience: # 熔断器配置 circuit_breaker_enabled: true failure_threshold: 5 timeout: 30s # 重试配置 retry_enabled: true max_retries: 3 retry_delay: 100ms saga: # 分布式事务配置 default_timeout: 30s max_retries: 3 enable_persistence: false hooks: # 钩子系统配置 default_timeout: 30s track_duration: true error_strategy: "continue" ``` ## 📋 **监控仪表板** ### **推荐监控栈** 1. **链路追踪**: Jaeger UI - 地址: `http://localhost:16686` - 查看完整请求链路 2. **指标监控**: Prometheus + Grafana - Prometheus: `http://localhost:9090` - Grafana: `http://localhost:3000` 3. **应用指标**: 内置指标端点 - 地址: `http://localhost:8080/metrics` ### **关键监控指标** ```yaml # 告警规则建议 groups: - name: tyapi-server rules: - alert: HighErrorRate expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1 - alert: CircuitBreakerOpen expr: circuit_breaker_state{state="open"} > 0 - alert: SagaFailure expr: rate(saga_failed_total[5m]) > 0.05 - alert: HighLatency expr: histogram_quantile(0.95, http_request_duration_seconds) > 1 ``` ## 🔧 **性能优化建议** ### **生产环境配置** 1. **追踪采样率**: 建议设置为 0.01-0.1 (1%-10%) 2. **指标收集**: 启用所有核心指标,按需启用业务指标 3. **熔断器阈值**: 根据服务 SLA 调整失败阈值 4. **钩子超时**: 设置合理的钩子执行超时时间 ### **扩展性考虑** 1. **水平扩展**: 所有组件都支持多实例部署 2. **状态无关**: 追踪和指标数据通过外部系统存储 3. **配置热更新**: 支持运行时配置调整 ## 🎯 **最佳实践** ### **链路追踪** - 在关键业务操作中主动创建 Span - 使用有意义的操作名称 - 添加重要的标签和属性 ### **指标收集** - 合理设置指标标签,避免高基数 - 定期清理不再使用的指标 - 使用直方图记录耗时分布 ### **弹性设计** - 在外部服务调用时使用熔断器 - 对瞬时失败使用重试机制 - 设计优雅降级策略 ### **事件钩子** - 保持钩子函数简单快速 - 使用异步钩子处理耗时操作 - 合理设置钩子优先级 ## 🔍 **故障排查** ### **常见问题** 1. **追踪数据丢失** - 检查 OTLP 端点连接性 - 确认采样率配置 - 查看应用日志中的追踪错误 2. **指标不更新** - 验证 Prometheus 抓取配置 - 检查指标端点可访问性 - 确认指标注册成功 3. **熔断器异常触发** - 检查失败阈值设置 - 分析下游服务健康状态 - 调整超时时间 ## 🏆 **集成完成状态** | 特性模块 | 实现状态 | 容器集成 | 中间件 | 配置支持 | 文档完整度 | | ---------- | -------- | -------- | ------------- | -------- | ---------- | | 链路追踪 | ✅ 100% | ✅ 完成 | ✅ 已集成 | ✅ 完整 | ✅ 完整 | | 指标监控 | ✅ 100% | ✅ 完成 | ✅ 已集成 | ✅ 完整 | ✅ 完整 | | 熔断器 | ✅ 100% | ✅ 完成 | ⚠️ 手动集成 | ✅ 完整 | ✅ 完整 | | 重试机制 | ✅ 100% | ✅ 完成 | ⚠️ 手动集成 | ✅ 完整 | ✅ 完整 | | 分布式事务 | ✅ 100% | ✅ 完成 | ⚠️ 手动集成 | ✅ 完整 | ✅ 完整 | | 钩子系统 | ✅ 100% | ✅ 完成 | ⚠️ 应用级集成 | ✅ 完整 | ✅ 完整 | ## 🎉 **总结** TYAPI Server 现已完成所有企业级高级特性的完整集成: ✅ **已完成的核心能力**: - 分布式链路追踪 (OpenTelemetry + OTLP) - 全方位指标监控 (Prometheus + 业务指标) - 多层次弹性恢复 (熔断器 + 重试机制) - 分布式事务管理 (Saga 模式) - 灵活事件钩子系统 ✅ **生产就绪特性**: - 完整的容器依赖注入 - 自动化中间件集成 - 优雅的生命周期管理 - 完善的配置系统 - 详细的监控指标 ✅ **开发体验**: - 编译零错误 - 热插拔组件设计 - 丰富的使用示例 - 完整的故障排查指南 现在您的 TYAPI Server 已经具备了企业级产品的所有核心监控和弹性能力!🚀