package main import ( "context" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin" "github.com/joho/godotenv" "go.uber.org/zap" ) var logger *zap.Logger func main() { // 初始化日志 var err error logger, err = zap.NewProduction() if err != nil { panic(fmt.Sprintf("Failed to initialize logger: %v", err)) } defer logger.Sync() // 加载环境变量 if err := godotenv.Load(); err != nil { logger.Warn("No .env file found, using system environment variables") } // 设置Gin模式 mode := getEnv("GIN_MODE", "debug") gin.SetMode(mode) // 创建路由 router := setupRouter() // 获取端口 port := getEnv("PORT", "8080") // 创建HTTP服务器 srv := &http.Server{ Addr: ":" + port, Handler: router, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, IdleTimeout: 60 * time.Second, } // 在单独的goroutine中启动服务器 go func() { logger.Info("Starting server", zap.String("port", port), zap.String("mode", mode)) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { logger.Fatal("Failed to start server", zap.Error(err)) } }() // 等待中断信号来优雅地关闭服务器 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit logger.Info("Shutting down server...") // 给服务器5秒钟来完成正在处理的请求 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { logger.Fatal("Server forced to shutdown", zap.Error(err)) } logger.Info("Server exited") } func setupRouter() *gin.Engine { router := gin.New() // 使用自定义中间件 router.Use(ginZapLogger(logger), ginZapRecovery(logger, true)) // 基本路由 router.GET("/", handleHome) router.GET("/ping", handlePing) router.GET("/health", handleHealth) router.GET("/version", handleVersion) // API组 api := router.Group("/api/v1") { api.GET("/status", handleAPIStatus) api.GET("/time", handleTime) api.POST("/echo", handleEcho) } return router } // 处理函数 func handleHome(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "Welcome to Golang Demo API", "version": "1.0.0", "environment": getEnv("GIN_MODE", "development"), "timestamp": time.Now().Format(time.RFC3339), }) } func handlePing(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "pong", "time": time.Now().Unix(), }) } func handleHealth(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "status": "healthy", "timestamp": time.Now().Format(time.RFC3339), "uptime": time.Since(startTime).String(), }) } func handleVersion(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "version": "1.0.0", "build_time": buildTime, "go_version": "1.21+", "git_commit": gitCommit, }) } func handleAPIStatus(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "api_version": "v1", "status": "active", "endpoints": []string{ "GET /api/v1/status", "GET /api/v1/time", "POST /api/v1/echo", }, }) } func handleTime(c *gin.Context) { now := time.Now() c.JSON(http.StatusOK, gin.H{ "timestamp": now.Unix(), "iso": now.Format(time.RFC3339), "utc": now.UTC().Format(time.RFC3339), "timezone": now.Location().String(), }) } func handleEcho(c *gin.Context) { var body map[string]interface{} if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": "Invalid JSON", "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "echo": body, "timestamp": time.Now().Format(time.RFC3339), "client_ip": c.ClientIP(), }) } // 工具函数 func getEnv(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue } // 构建时注入的变量 var ( startTime = time.Now() buildTime = "unknown" gitCommit = "unknown" ) // Gin中间件 func ginZapLogger(logger *zap.Logger) gin.HandlerFunc { return gin.LoggerWithWriter(gin.DefaultWriter) } func ginZapRecovery(logger *zap.Logger, stack bool) gin.HandlerFunc { return gin.Recovery() }