httpServer.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package servers
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/gin-contrib/pprof"
  7. "github.com/gin-gonic/gin"
  8. ginprometheus "github.com/zsais/go-gin-prometheus"
  9. "gogs.tyduyong.com/duyong/dy-admin/internal/iam/config"
  10. "gogs.tyduyong.com/duyong/dy-pkg/app/middleware"
  11. "gogs.tyduyong.com/duyong/dy-pkg/app/response"
  12. "gogs.tyduyong.com/duyong/dy-pkg/app/version"
  13. "gogs.tyduyong.com/duyong/dy-pkg/logs"
  14. "log"
  15. "net"
  16. "net/http"
  17. "strconv"
  18. "strings"
  19. "time"
  20. )
  21. // CertKey 证书结构
  22. type CertKey struct {
  23. // CertFile is a file containing a PEM-encoded certificate, and possibly the complete certificate chain
  24. CertFile string
  25. // KeyFile is a file containing a PEM-encoded private key for the certificate specified by CertFile
  26. KeyFile string
  27. }
  28. // SecureServeInfo 开启https时的结构
  29. type SecureServeInfo struct {
  30. BindAddress string
  31. BindPort int
  32. CertKey CertKey
  33. }
  34. func (s *SecureServeInfo) Address() string {
  35. return net.JoinHostPort(s.BindAddress, strconv.Itoa(s.BindPort))
  36. }
  37. // httpAPIServer Http&Https封装
  38. type httpAPIServer struct {
  39. *gin.Engine
  40. middlewares []string
  41. healthz bool
  42. enableMetrics bool
  43. enableProfiling bool
  44. insecureAddress string
  45. secureInfo *SecureServeInfo
  46. insecureServer, secureServer *http.Server
  47. }
  48. // newHttpServer 构建http服务配置
  49. func newHttpServer(cfg *config.Config) *httpAPIServer {
  50. gin.SetMode(cfg.ServerRunOptions.Mode)
  51. httpServer := &httpAPIServer{
  52. Engine: gin.New(),
  53. middlewares: cfg.ServerRunOptions.Middlewares,
  54. healthz: cfg.ServerRunOptions.Healthz,
  55. enableMetrics: cfg.FeatureOptions.EnableMetrics,
  56. enableProfiling: cfg.FeatureOptions.EnableProfiling,
  57. insecureAddress: net.JoinHostPort(cfg.InsecureServeOptions.BindAddress, strconv.Itoa(cfg.InsecureServeOptions.BindPort)),
  58. secureInfo: &SecureServeInfo{
  59. BindAddress: cfg.SecureServingOptions.BindAddress,
  60. BindPort: cfg.SecureServingOptions.BindPort,
  61. CertKey: CertKey{
  62. CertFile: cfg.SecureServingOptions.ServerCert.CertKey.CertFile,
  63. KeyFile: cfg.SecureServingOptions.ServerCert.CertKey.KeyFile,
  64. },
  65. },
  66. }
  67. httpServer.Setup()
  68. httpServer.InstallMiddlewares()
  69. httpServer.InstallAPIs()
  70. return httpServer
  71. }
  72. func (s *httpAPIServer) Setup() {
  73. gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
  74. logs.Infof("%-6s %-s --> %s (%d handlers)", httpMethod, absolutePath, handlerName, nuHandlers)
  75. }
  76. }
  77. // InstallMiddlewares 根据配置,选定路由中间件
  78. func (s *httpAPIServer) InstallMiddlewares() {
  79. // 必选中间件
  80. s.Use(middleware.RequestID())
  81. s.Use(middleware.Context())
  82. // install custom middlewares
  83. for _, m := range s.middlewares {
  84. mw, ok := middleware.Middlewares[m]
  85. if !ok {
  86. logs.Warnf("can not find middleware: %s", m)
  87. continue
  88. }
  89. logs.Infof("install middleware: %s", m)
  90. s.Use(mw)
  91. }
  92. }
  93. // InstallAPIs 根据配置,设置制定的接口
  94. func (s *httpAPIServer) InstallAPIs() {
  95. // 健康检查接口
  96. if s.healthz {
  97. s.GET("/healthz", func(c *gin.Context) {
  98. response.WriteResponse(c, nil, map[string]string{"status": "ok"})
  99. })
  100. }
  101. // 监控接口
  102. if s.enableMetrics {
  103. prometheus := ginprometheus.NewPrometheus("gin")
  104. prometheus.Use(s.Engine)
  105. }
  106. // install pprof handler
  107. if s.enableProfiling {
  108. pprof.Register(s.Engine)
  109. }
  110. s.GET("/version", func(c *gin.Context) {
  111. response.WriteResponse(c, nil, version.Get())
  112. })
  113. }
  114. // Run 启动服务
  115. func (s *httpAPIServer) Run() {
  116. s.insecureServer = &http.Server{
  117. Addr: s.insecureAddress,
  118. Handler: s,
  119. }
  120. s.secureServer = &http.Server{
  121. Addr: s.secureInfo.Address(),
  122. Handler: s,
  123. }
  124. go func() {
  125. logs.Infof("Start to listening the incoming requests on http address: %s", s.insecureAddress)
  126. if err := s.insecureServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
  127. logs.Fatal(err.Error())
  128. return
  129. }
  130. logs.Infof("Server on %s stopped", s.insecureAddress)
  131. }()
  132. go func() {
  133. key, cert := s.secureInfo.CertKey.KeyFile, s.secureInfo.CertKey.CertFile
  134. if cert == "" || key == "" || s.secureInfo.BindPort == 0 {
  135. return
  136. }
  137. logs.Infof("Start to listening the incoming requests on https address: %s", s.secureInfo.Address())
  138. if err := s.secureServer.ListenAndServeTLS(cert, key); err != nil && !errors.Is(err, http.ErrServerClosed) {
  139. logs.Fatal(err.Error())
  140. return
  141. }
  142. logs.Infof("Server on %s stopped", s.secureInfo.Address())
  143. }()
  144. // Ping the server to make sure the router is working.
  145. go func() {
  146. if s.healthz {
  147. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  148. defer cancel()
  149. if s.healthz {
  150. if err := s.ping(ctx); err != nil {
  151. return
  152. }
  153. }
  154. }
  155. }()
  156. return
  157. }
  158. // Close 关闭服务
  159. func (s *httpAPIServer) Close() {
  160. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  161. defer cancel()
  162. if err := s.secureServer.Shutdown(ctx); err != nil {
  163. logs.Warnf("Shutdown secure server failed: %s", err.Error())
  164. }
  165. if err := s.insecureServer.Shutdown(ctx); err != nil {
  166. logs.Warnf("Shutdown insecure server failed: %s", err.Error())
  167. }
  168. }
  169. func (s *httpAPIServer) ping(ctx context.Context) error {
  170. url := fmt.Sprintf("http://%s/healthz", s.insecureAddress)
  171. if strings.Contains(s.insecureAddress, "0.0.0.0") {
  172. url = fmt.Sprintf("http://127.0.0.1:%s/healthz", strings.Split(s.insecureAddress, ":")[1])
  173. }
  174. for {
  175. req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
  176. if err != nil {
  177. return err
  178. }
  179. resp, err := http.DefaultClient.Do(req)
  180. if err == nil && resp.StatusCode == http.StatusOK {
  181. logs.Info("The router has been deployed successfully.")
  182. resp.Body.Close()
  183. return nil
  184. }
  185. // Sleep for a second to continue the next ping.
  186. logs.Info("Waiting for the router, retry in 1 second.")
  187. time.Sleep(1 * time.Second)
  188. select {
  189. case <-ctx.Done():
  190. log.Fatal("can not ping http server with in the specified time interval.")
  191. default:
  192. }
  193. }
  194. }