303 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			303 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package http
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"sort"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/gin-gonic/gin"
 | |
| 	swaggerFiles "github.com/swaggo/files"
 | |
| 	ginSwagger "github.com/swaggo/gin-swagger"
 | |
| 	"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)...)
 | |
| 
 | |
| 	r.logger.Info("已注册HTTP处理器",
 | |
| 		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)
 | |
| 
 | |
| 	r.logger.Info("已注册中间件",
 | |
| 		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,
 | |
| 	}
 | |
| 
 | |
| 	r.logger.Info("正在启动HTTP服务器", zap.String("addr", addr))
 | |
| 
 | |
| 	// 启动服务器
 | |
| 	if err := r.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
 | |
| 		r.logger.Error("HTTP服务器启动失败", 
 | |
| 			zap.String("addr", addr),
 | |
| 			zap.Error(err))
 | |
| 		return fmt.Errorf("failed to start server: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	r.logger.Info("HTTP服务器启动成功", zap.String("addr", addr))
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Stop 停止路由器
 | |
| func (r *GinRouter) Stop(ctx context.Context) error {
 | |
| 	if r.server == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	r.logger.Info("正在关闭HTTP服务器...")
 | |
| 
 | |
| 	// 优雅关闭服务器
 | |
| 	if err := r.server.Shutdown(ctx); err != nil {
 | |
| 		r.logger.Error("优雅关闭服务器失败", zap.Error(err))
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	r.logger.Info("HTTP服务器已关闭")
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetEngine 获取Gin引擎
 | |
| func (r *GinRouter) GetEngine() *gin.Engine {
 | |
| 	return r.engine
 | |
| }
 | |
| 
 | |
| // applyMiddlewares 应用中间件
 | |
| func (r *GinRouter) applyMiddlewares() {
 | |
| 	// 按优先级排序中间件
 | |
| 	sort.Slice(r.middlewares, func(i, j int) bool {
 | |
| 		return r.middlewares[i].GetPriority() > r.middlewares[j].GetPriority()
 | |
| 	})
 | |
| 
 | |
| 	// 应用全局中间件
 | |
| 	for _, middleware := range r.middlewares {
 | |
| 		if middleware.IsGlobal() {
 | |
| 			r.engine.Use(middleware.Handle())
 | |
| 			r.logger.Debug("已应用全局中间件",
 | |
| 				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,
 | |
| 		})
 | |
| 	})
 | |
| 
 | |
| 	// 详细健康检查
 | |
| 	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,
 | |
| 		})
 | |
| 	})
 | |
| 
 | |
| 	// 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(),
 | |
| 		})
 | |
| 	})
 | |
| 
 | |
| 	// 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"))
 | |
| 	}
 | |
| 
 | |
| 	// 404处理
 | |
| 	r.engine.NoRoute(func(c *gin.Context) {
 | |
| 		c.JSON(http.StatusNotFound, gin.H{
 | |
| 			"success":   false,
 | |
| 			"message":   "路由未找到",
 | |
| 			"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,
 | |
| 			"message":   "请求方法不允许",
 | |
| 			"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")
 | |
| 	}
 | |
| }
 |