server.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package bootstrap
  2. import (
  3. "net/http"
  4. "path/filepath"
  5. "strconv"
  6. "strings"
  7. "time"
  8. routers "dbview/service/internal/modules"
  9. "github.com/gin-contrib/cors"
  10. "github.com/gin-gonic/gin"
  11. "go.uber.org/zap"
  12. )
  13. // Server HTTP服务器
  14. type Server struct {
  15. app *App
  16. engine *gin.Engine
  17. }
  18. // MountStaticFiles 由命令行标志控制(在 package flags.go 中注册,入口处调用 Parse)
  19. // NewServer 创建新的服务器实例
  20. func NewServer(app *App) *Server {
  21. return &Server{
  22. app: app,
  23. }
  24. }
  25. // Setup 设置服务器
  26. func (s *Server) Setup() {
  27. // 创建Gin引擎
  28. s.engine = gin.Default()
  29. // 设置中间件(已优化重复CORS)
  30. s.setupMiddleware()
  31. // 1. 先注册所有API路由(确保API路由优先)
  32. s.registerRoutes()
  33. // 2. 挂载本地静态文件(Vue打包的dist目录)
  34. if MountStaticFiles {
  35. s.mountStaticFiles()
  36. } else {
  37. s.app.Logger.Info("静态文件挂载已禁用(运行时参数控制)", zap.Bool("mount_flag", MountStaticFiles))
  38. }
  39. s.app.Logger.Info("HTTP服务器设置完成",
  40. zap.String("addr", s.app.Config.Server.Ip),
  41. zap.Bool("cors_enabled", true),
  42. zap.Bool("audit_enabled", s.app.Config.Audit.Enabled))
  43. }
  44. // 新增:挂载本地静态文件(不使用embed)
  45. func (s *Server) mountStaticFiles() {
  46. // 获取本地dist目录的绝对路径(确保程序能找到Vue打包后的文件)
  47. // 注意:dist目录需放在项目根目录(与main.go同级)
  48. distPath, err := filepath.Abs("dist")
  49. if err != nil {
  50. s.app.Logger.Error("获取静态文件目录失败", zap.Error(err))
  51. return
  52. }
  53. // 挂载静态文件到 /static 前缀(与API路由完全隔离,避免冲突)
  54. // 访问路径:/static/index.html → 对应本地 dist/index.html
  55. s.engine.StaticFS("/static", http.Dir(distPath))
  56. s.app.Logger.Info("静态文件挂载成功", zap.String("dist_path", distPath), zap.String("mount_path", "/static"))
  57. // 3. 处理Vue SPA前端路由(如 /dashboard、/settings 等前端路由)
  58. s.engine.NoRoute(func(c *gin.Context) {
  59. // 过滤API路由(避免API请求被误处理为前端路由)
  60. // 现有API前缀:/connection_storage、/db_connection、/db_view、/sql_execute、/api 等
  61. apiPrefixes := []string{
  62. "/connection_storage",
  63. "/db_connection",
  64. "/db_view",
  65. "/sql_execute",
  66. "/api",
  67. }
  68. for _, prefix := range apiPrefixes {
  69. if strings.HasPrefix(c.Request.URL.Path, prefix) {
  70. c.Status(http.StatusNotFound) // API路由不存在时返回404
  71. return
  72. }
  73. }
  74. // 非API路由:返回dist目录下的index.html(由前端路由处理)
  75. indexPath := filepath.Join(distPath, "index.html")
  76. c.File(indexPath)
  77. })
  78. }
  79. // setupMiddleware 设置中间件(清理重复CORS)
  80. func (s *Server) setupMiddleware() {
  81. // 依赖注入中间件 - 暂时注释,等待 middleware 包实现
  82. // s.engine.Use(middleware.InjectDependencies(s.app.StorageManager, s.app.ConnectionPool))
  83. // 自定义CORS配置(保留自定义配置,移除重复的cors.Default())
  84. s.engine.Use(cors.New(cors.Config{
  85. AllowOrigins: []string{"*"}, // 允许所有来源
  86. AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, // 允许的方法
  87. AllowHeaders: []string{"Content-Type", "Authorization", "X-Requested-With"}, // 允许的头部
  88. ExposeHeaders: []string{"Content-Length"}, // 可暴露的头部
  89. AllowCredentials: true, // 允许携带凭据
  90. MaxAge: 12 * time.Hour, // 缓存时间
  91. }))
  92. // 客户端地址中间件 - 暂时注释,等待 middleware 包实现
  93. // s.engine.Use(middleware.ClientAddrMiddleware())
  94. // Gin恢复中间件(异常恢复)
  95. s.engine.Use(gin.Recovery())
  96. // 使用修复后的日志中间件 - 暂时注释,等待 middleware 包实现
  97. // s.engine.Use(middleware.RequestLoggerMiddleware())
  98. }
  99. // registerRoutes 注册路由(现有逻辑不变)
  100. func (s *Server) registerRoutes() {
  101. // 注册模块路由
  102. routers.RegisterRoutes(s.engine, s.app.StorageManager, s.app.TaskManager, s.app.ConnectionPool, s.app.Config.AI)
  103. // 基础健康检查路由
  104. s.engine.GET("/health", func(c *gin.Context) {
  105. c.JSON(200, gin.H{
  106. "status": "ok",
  107. "time": time.Now().Format(time.RFC3339),
  108. })
  109. })
  110. s.app.Logger.Info("路由注册完成")
  111. }
  112. // Start 启动服务器(现有逻辑不变)
  113. func (s *Server) Start() error {
  114. s.app.Logger.Info("HTTP服务器启动完成", zap.String("IP:Port", s.app.Config.Server.Ip+":"+strconv.Itoa(s.app.Config.Server.Port)))
  115. addr := s.app.Config.Server.Ip + ":" + strconv.Itoa(s.app.Config.Server.Port)
  116. return s.engine.Run(addr)
  117. }