Files
tyapi-server/internal/shared/http/router.go
2026-03-10 17:28:04 +08:00

316 lines
8.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
// 加载HTML模板企业报告等页面
// 这里直接加载项目根目录下的 qiye.html后续如有更多模板可改为 LoadHTMLGlob
engine.LoadHTMLFiles("qiye.html")
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 {
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()
})
// 应用全局中间件
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")
}
}