package bootstrap import ( "context" "designs/app/common/request" "designs/app/common/response" "designs/config" "designs/global" "designs/route" "fmt" "go.uber.org/zap" "log" "net/http" "os" "os/signal" "runtime/debug" "syscall" "time" "github.com/gin-gonic/gin" ) // 回收致命错误 func CustomRecovery(c *gin.Context) { defer func() { if r := recover(); r != nil { if v, ok := r.(request.ValidateError); ok { response.ParameterError(c, v) return } //打印错误堆栈信息 errTitle := fmt.Sprintf("panic: %v", r) errMsg := fmt.Sprintf("stack: %v", string(debug.Stack())) global.App.Log.Error("custom_recovery", zap.Any("info", errTitle), zap.Stack("stack")) response.ServerError(c, errTitle+errMsg) } }() //继续后续接口调用 c.Next() } func corsMiddleware() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", "*") // 或者指定允许的源 c.Writer.Header().Set("Access-Control-Max-Age", "86400") // 缓存请求信息 c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE") c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Length, Content-Type, Authorization, X-Requested-With") c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Type") c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } } func setupRouter() *gin.Engine { if config.Get("app.env") == "production" { gin.SetMode(gin.ReleaseMode) } router := gin.New() router.Use(gin.Logger(), CustomRecovery) router.Use(corsMiddleware()) // 跨域处理 //router.Use(middleware.Cors()) // 前端项目静态资源 // router.StaticFile("/", "./static/dist/index.html") // router.Static("/assets", "./static/dist/assets") // router.StaticFile("/favicon.ico", "./static/dist/favicon.ico") // 其他静态资源 // router.Static("/public", "./static") // router.Static("/storage", "./storage/app/public") // 注册 api 分组路由 apiGroup := router.Group("") route.SetApiGroupRoutes(apiGroup) return router } func RunServer() { r := setupRouter() srv := &http.Server{ Addr: ":" + config.Get("app.port"), ReadTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, Handler: r, } fmt.Println("Starting server at port " + config.Get("app.port") + " ...") go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }() // 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间) quit := make(chan os.Signal) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutdown Server ...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } log.Println("Server exiting") }