router.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package bootstrap
  2. import (
  3. "context"
  4. "designs/app/common/request"
  5. "designs/app/common/response"
  6. "designs/config"
  7. "designs/global"
  8. "designs/route"
  9. "fmt"
  10. "go.uber.org/zap"
  11. "log"
  12. "net/http"
  13. "os"
  14. "os/signal"
  15. "runtime/debug"
  16. "syscall"
  17. "time"
  18. "github.com/gin-gonic/gin"
  19. )
  20. // 回收致命错误
  21. func CustomRecovery(c *gin.Context) {
  22. defer func() {
  23. if r := recover(); r != nil {
  24. if v, ok := r.(request.ValidateError); ok {
  25. response.ParameterError(c, v)
  26. return
  27. }
  28. //打印错误堆栈信息
  29. errTitle := fmt.Sprintf("panic: %v", r)
  30. errMsg := fmt.Sprintf("stack: %v", string(debug.Stack()))
  31. global.App.Log.Error("custom_recovery", zap.Any("info", errTitle), zap.Stack("stack"))
  32. response.ServerError(c, errTitle+errMsg)
  33. }
  34. }()
  35. //继续后续接口调用
  36. c.Next()
  37. }
  38. func corsMiddleware() gin.HandlerFunc {
  39. return func(c *gin.Context) {
  40. c.Writer.Header().Set("Access-Control-Allow-Origin", "*") // 或者指定允许的源
  41. c.Writer.Header().Set("Access-Control-Max-Age", "86400") // 缓存请求信息
  42. c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
  43. c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Length, Content-Type, Authorization, X-Requested-With")
  44. c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Type")
  45. c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
  46. if c.Request.Method == "OPTIONS" {
  47. c.AbortWithStatus(204)
  48. return
  49. }
  50. c.Next()
  51. }
  52. }
  53. func setupRouter() *gin.Engine {
  54. if config.Get("app.env") == "production" {
  55. gin.SetMode(gin.ReleaseMode)
  56. }
  57. router := gin.New()
  58. router.Use(gin.Logger(), CustomRecovery)
  59. router.Use(corsMiddleware())
  60. // 跨域处理
  61. //router.Use(middleware.Cors())
  62. // 前端项目静态资源
  63. // router.StaticFile("/", "./static/dist/index.html")
  64. // router.Static("/assets", "./static/dist/assets")
  65. // router.StaticFile("/favicon.ico", "./static/dist/favicon.ico")
  66. // 其他静态资源
  67. // router.Static("/public", "./static")
  68. // router.Static("/storage", "./storage/app/public")
  69. // 注册 api 分组路由
  70. apiGroup := router.Group("")
  71. route.SetApiGroupRoutes(apiGroup)
  72. return router
  73. }
  74. func RunServer() {
  75. r := setupRouter()
  76. srv := &http.Server{
  77. Addr: ":" + config.Get("app.port"),
  78. ReadTimeout: 60 * time.Second,
  79. WriteTimeout: 60 * time.Second,
  80. Handler: r,
  81. }
  82. fmt.Println("Starting server at port " + config.Get("app.port") + " ...")
  83. go func() {
  84. if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
  85. log.Fatalf("listen: %s\n", err)
  86. }
  87. }()
  88. // 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
  89. quit := make(chan os.Signal)
  90. signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
  91. <-quit
  92. log.Println("Shutdown Server ...")
  93. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  94. defer cancel()
  95. if err := srv.Shutdown(ctx); err != nil {
  96. log.Fatal("Server Shutdown:", err)
  97. }
  98. log.Println("Server exiting")
  99. }