| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | package http | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/gin-gonic/gin" | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 	swaggerFiles "github.com/swaggo/files" | 
					
						
							|  |  |  | 	ginSwagger "github.com/swaggo/gin-swagger" | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 	"go.uber.org/zap" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"tyapi-server/internal/config" | 
					
						
							|  |  |  | 	"tyapi-server/internal/shared/interfaces" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GinRouter Gin路由器实现 | 
					
						
							|  |  |  | type GinRouter struct { | 
					
						
							|  |  |  | 	engine      *gin.Engine | 
					
						
							|  |  |  | 	config      *config.Config | 
					
						
							|  |  |  | 	logger      *zap.Logger | 
					
						
							|  |  |  | 	middlewares []interfaces.Middleware | 
					
						
							|  |  |  | 	server      *http.Server | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewGinRouter 创建Gin路由器 | 
					
						
							|  |  |  | func NewGinRouter(cfg *config.Config, logger *zap.Logger) *GinRouter { | 
					
						
							|  |  |  | 	// 设置Gin模式 | 
					
						
							|  |  |  | 	if cfg.App.IsProduction() { | 
					
						
							|  |  |  | 		gin.SetMode(gin.ReleaseMode) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		gin.SetMode(gin.DebugMode) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 创建Gin引擎 | 
					
						
							|  |  |  | 	engine := gin.New() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &GinRouter{ | 
					
						
							|  |  |  | 		engine:      engine, | 
					
						
							|  |  |  | 		config:      cfg, | 
					
						
							|  |  |  | 		logger:      logger, | 
					
						
							|  |  |  | 		middlewares: make([]interfaces.Middleware, 0), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RegisterHandler 注册处理器 | 
					
						
							|  |  |  | func (r *GinRouter) RegisterHandler(handler interfaces.HTTPHandler) error { | 
					
						
							|  |  |  | 	// 应用处理器中间件 | 
					
						
							|  |  |  | 	middlewares := handler.GetMiddlewares() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 注册路由 | 
					
						
							|  |  |  | 	r.engine.Handle(handler.GetMethod(), handler.GetPath(), append(middlewares, handler.Handle)...) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 	r.logger.Info("已注册HTTP处理器", | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 		zap.String("method", handler.GetMethod()), | 
					
						
							|  |  |  | 		zap.String("path", handler.GetPath())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RegisterMiddleware 注册中间件 | 
					
						
							|  |  |  | func (r *GinRouter) RegisterMiddleware(middleware interfaces.Middleware) error { | 
					
						
							|  |  |  | 	r.middlewares = append(r.middlewares, middleware) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 	r.logger.Info("已注册中间件", | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 		zap.String("name", middleware.GetName()), | 
					
						
							|  |  |  | 		zap.Int("priority", middleware.GetPriority())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RegisterGroup 注册路由组 | 
					
						
							|  |  |  | func (r *GinRouter) RegisterGroup(prefix string, middlewares ...gin.HandlerFunc) gin.IRoutes { | 
					
						
							|  |  |  | 	return r.engine.Group(prefix, middlewares...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetRoutes 获取路由信息 | 
					
						
							|  |  |  | func (r *GinRouter) GetRoutes() gin.RoutesInfo { | 
					
						
							|  |  |  | 	return r.engine.Routes() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Start 启动路由器 | 
					
						
							|  |  |  | func (r *GinRouter) Start(addr string) error { | 
					
						
							|  |  |  | 	// 应用中间件(按优先级排序) | 
					
						
							|  |  |  | 	r.applyMiddlewares() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 创建HTTP服务器 | 
					
						
							|  |  |  | 	r.server = &http.Server{ | 
					
						
							|  |  |  | 		Addr:         addr, | 
					
						
							|  |  |  | 		Handler:      r.engine, | 
					
						
							|  |  |  | 		ReadTimeout:  r.config.Server.ReadTimeout, | 
					
						
							|  |  |  | 		WriteTimeout: r.config.Server.WriteTimeout, | 
					
						
							|  |  |  | 		IdleTimeout:  r.config.Server.IdleTimeout, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 	r.logger.Info("正在启动HTTP服务器", zap.String("addr", addr)) | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 启动服务器 | 
					
						
							|  |  |  | 	if err := r.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { | 
					
						
							| 
									
										
										
										
											2025-07-28 16:19:53 +08:00
										 |  |  | 		r.logger.Error("HTTP服务器启动失败",  | 
					
						
							|  |  |  | 			zap.String("addr", addr), | 
					
						
							|  |  |  | 			zap.Error(err)) | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 		return fmt.Errorf("failed to start server: %w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-28 16:19:53 +08:00
										 |  |  | 	r.logger.Info("HTTP服务器启动成功", zap.String("addr", addr)) | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stop 停止路由器 | 
					
						
							|  |  |  | func (r *GinRouter) Stop(ctx context.Context) error { | 
					
						
							|  |  |  | 	if r.server == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 	r.logger.Info("正在关闭HTTP服务器...") | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 优雅关闭服务器 | 
					
						
							|  |  |  | 	if err := r.server.Shutdown(ctx); err != nil { | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 		r.logger.Error("优雅关闭服务器失败", zap.Error(err)) | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 	r.logger.Info("HTTP服务器已关闭") | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetEngine 获取Gin引擎 | 
					
						
							|  |  |  | func (r *GinRouter) GetEngine() *gin.Engine { | 
					
						
							|  |  |  | 	return r.engine | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // applyMiddlewares 应用中间件 | 
					
						
							|  |  |  | func (r *GinRouter) applyMiddlewares() { | 
					
						
							| 
									
										
										
										
											2025-08-28 17:09:21 +08:00
										 |  |  | 	// 按优先级排序中间件,优先级相同时按名称排序确保稳定性 | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 	sort.Slice(r.middlewares, func(i, j int) bool { | 
					
						
							| 
									
										
										
										
											2025-08-28 17:09:21 +08:00
										 |  |  | 		priorityI := r.middlewares[i].GetPriority() | 
					
						
							|  |  |  | 		priorityJ := r.middlewares[j].GetPriority() | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		// 如果优先级不同,按优先级降序排列 | 
					
						
							|  |  |  | 		if priorityI != priorityJ { | 
					
						
							|  |  |  | 			return priorityI > priorityJ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		// 如果优先级相同,按名称排序确保稳定性 | 
					
						
							|  |  |  | 		return r.middlewares[i].GetName() < r.middlewares[j].GetName() | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 应用全局中间件 | 
					
						
							|  |  |  | 	for _, middleware := range r.middlewares { | 
					
						
							|  |  |  | 		if middleware.IsGlobal() { | 
					
						
							|  |  |  | 			r.engine.Use(middleware.Handle()) | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 			r.logger.Debug("已应用全局中间件", | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 				zap.String("name", middleware.GetName()), | 
					
						
							|  |  |  | 				zap.Int("priority", middleware.GetPriority())) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetupDefaultRoutes 设置默认路由 | 
					
						
							|  |  |  | func (r *GinRouter) SetupDefaultRoutes() { | 
					
						
							|  |  |  | 	// 健康检查 | 
					
						
							|  |  |  | 	r.engine.GET("/health", func(c *gin.Context) { | 
					
						
							|  |  |  | 		c.JSON(http.StatusOK, gin.H{ | 
					
						
							|  |  |  | 			"status":    "healthy", | 
					
						
							|  |  |  | 			"timestamp": time.Now().Unix(), | 
					
						
							|  |  |  | 			"service":   r.config.App.Name, | 
					
						
							|  |  |  | 			"version":   r.config.App.Version, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 	// 详细健康检查 | 
					
						
							|  |  |  | 	r.engine.GET("/health/detailed", func(c *gin.Context) { | 
					
						
							|  |  |  | 		c.JSON(http.StatusOK, gin.H{ | 
					
						
							|  |  |  | 			"status":      "healthy", | 
					
						
							|  |  |  | 			"timestamp":   time.Now().Unix(), | 
					
						
							|  |  |  | 			"service":     r.config.App.Name, | 
					
						
							|  |  |  | 			"version":     r.config.App.Version, | 
					
						
							|  |  |  | 			"uptime":      time.Now().Unix(), | 
					
						
							|  |  |  | 			"environment": r.config.App.Env, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 	// API信息 | 
					
						
							|  |  |  | 	r.engine.GET("/info", func(c *gin.Context) { | 
					
						
							|  |  |  | 		c.JSON(http.StatusOK, gin.H{ | 
					
						
							|  |  |  | 			"name":        r.config.App.Name, | 
					
						
							|  |  |  | 			"version":     r.config.App.Version, | 
					
						
							|  |  |  | 			"environment": r.config.App.Env, | 
					
						
							|  |  |  | 			"timestamp":   time.Now().Unix(), | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 	// Swagger文档路由 (仅在开发环境启用) | 
					
						
							|  |  |  | 	if !r.config.App.IsProduction() { | 
					
						
							|  |  |  | 		// Swagger UI | 
					
						
							|  |  |  | 		r.engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// API文档重定向 | 
					
						
							|  |  |  | 		r.engine.GET("/docs", func(c *gin.Context) { | 
					
						
							|  |  |  | 			c.Redirect(http.StatusMovedPermanently, "/swagger/index.html") | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// API文档信息 | 
					
						
							|  |  |  | 		r.engine.GET("/api/docs", func(c *gin.Context) { | 
					
						
							|  |  |  | 			c.JSON(http.StatusOK, gin.H{ | 
					
						
							|  |  |  | 				"swagger_ui":   fmt.Sprintf("http://%s/swagger/index.html", c.Request.Host), | 
					
						
							|  |  |  | 				"openapi_json": fmt.Sprintf("http://%s/swagger/doc.json", c.Request.Host), | 
					
						
							|  |  |  | 				"redoc":        fmt.Sprintf("http://%s/redoc", c.Request.Host), | 
					
						
							|  |  |  | 				"message":      "API文档已可用", | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		r.logger.Info("Swagger documentation enabled", | 
					
						
							|  |  |  | 			zap.String("swagger_url", "/swagger/index.html"), | 
					
						
							|  |  |  | 			zap.String("docs_url", "/docs"), | 
					
						
							|  |  |  | 			zap.String("api_docs_url", "/api/docs")) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 	// 404处理 | 
					
						
							|  |  |  | 	r.engine.NoRoute(func(c *gin.Context) { | 
					
						
							|  |  |  | 		c.JSON(http.StatusNotFound, gin.H{ | 
					
						
							|  |  |  | 			"success":   false, | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 			"message":   "路由未找到", | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 			"path":      c.Request.URL.Path, | 
					
						
							|  |  |  | 			"method":    c.Request.Method, | 
					
						
							|  |  |  | 			"timestamp": time.Now().Unix(), | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 405处理 | 
					
						
							|  |  |  | 	r.engine.NoMethod(func(c *gin.Context) { | 
					
						
							|  |  |  | 		c.JSON(http.StatusMethodNotAllowed, gin.H{ | 
					
						
							|  |  |  | 			"success":   false, | 
					
						
							| 
									
										
										
										
											2025-07-02 16:17:59 +08:00
										 |  |  | 			"message":   "请求方法不允许", | 
					
						
							| 
									
										
										
										
											2025-06-30 19:21:56 +08:00
										 |  |  | 			"path":      c.Request.URL.Path, | 
					
						
							|  |  |  | 			"method":    c.Request.Method, | 
					
						
							|  |  |  | 			"timestamp": time.Now().Unix(), | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // PrintRoutes 打印路由信息 | 
					
						
							|  |  |  | func (r *GinRouter) PrintRoutes() { | 
					
						
							|  |  |  | 	routes := r.GetRoutes() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r.logger.Info("Registered routes:") | 
					
						
							|  |  |  | 	for _, route := range routes { | 
					
						
							|  |  |  | 		r.logger.Info("Route", | 
					
						
							|  |  |  | 			zap.String("method", route.Method), | 
					
						
							|  |  |  | 			zap.String("path", route.Path), | 
					
						
							|  |  |  | 			zap.String("handler", route.Handler)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetStats 获取路由器统计信息 | 
					
						
							|  |  |  | func (r *GinRouter) GetStats() map[string]interface{} { | 
					
						
							|  |  |  | 	routes := r.GetRoutes() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stats := map[string]interface{}{ | 
					
						
							|  |  |  | 		"total_routes":      len(routes), | 
					
						
							|  |  |  | 		"total_middlewares": len(r.middlewares), | 
					
						
							|  |  |  | 		"server_config": map[string]interface{}{ | 
					
						
							|  |  |  | 			"read_timeout":  r.config.Server.ReadTimeout, | 
					
						
							|  |  |  | 			"write_timeout": r.config.Server.WriteTimeout, | 
					
						
							|  |  |  | 			"idle_timeout":  r.config.Server.IdleTimeout, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 按方法统计路由数量 | 
					
						
							|  |  |  | 	methodStats := make(map[string]int) | 
					
						
							|  |  |  | 	for _, route := range routes { | 
					
						
							|  |  |  | 		methodStats[route.Method]++ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	stats["routes_by_method"] = methodStats | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 中间件统计 | 
					
						
							|  |  |  | 	middlewareStats := make([]map[string]interface{}, 0, len(r.middlewares)) | 
					
						
							|  |  |  | 	for _, middleware := range r.middlewares { | 
					
						
							|  |  |  | 		middlewareStats = append(middlewareStats, map[string]interface{}{ | 
					
						
							|  |  |  | 			"name":     middleware.GetName(), | 
					
						
							|  |  |  | 			"priority": middleware.GetPriority(), | 
					
						
							|  |  |  | 			"global":   middleware.IsGlobal(), | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	stats["middlewares"] = middlewareStats | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return stats | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // EnableMetrics 启用指标收集 | 
					
						
							|  |  |  | func (r *GinRouter) EnableMetrics(collector interfaces.MetricsCollector) { | 
					
						
							|  |  |  | 	r.engine.Use(func(c *gin.Context) { | 
					
						
							|  |  |  | 		start := time.Now() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		c.Next() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		duration := time.Since(start).Seconds() | 
					
						
							|  |  |  | 		collector.RecordHTTPRequest(c.Request.Method, c.FullPath(), c.Writer.Status(), duration) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // EnableProfiling 启用性能分析 | 
					
						
							|  |  |  | func (r *GinRouter) EnableProfiling() { | 
					
						
							|  |  |  | 	if r.config.Development.EnableProfiler { | 
					
						
							|  |  |  | 		// 这里可以集成pprof | 
					
						
							|  |  |  | 		r.logger.Info("Profiling enabled") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |