Golang_demo/main.go

195 lines
4.1 KiB
Go
Raw Normal View History

2025-06-25 13:26:35 +08:00
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()
}