成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Golang GinWeb框架8-重定向/自定義中間件/認證/HTTPS支持/優雅重啟等

開發 前端
本文接著上文(Golang GinWeb框架7-靜態文件/模板渲染)繼續探索GinWeb框架.

[[356340]]

 簡介

本文接著上文(Golang GinWeb框架7-靜態文件/模板渲染)繼續探索GinWeb框架.

重定向

Gin返回一個HTTP重定向非常簡單, 使用Redirect方法即可. 內部和外部鏈接都支持.

  1. package main 
  2.  
  3. import ( 
  4.   "github.com/gin-gonic/gin" 
  5.   "net/http" 
  6.  
  7. func main() { 
  8.   r := gin.Default() 
  9.   r.GET("/test", func(c *gin.Context) { 
  10.     c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")  //重定向到外部鏈接 
  11.   }) 
  12.  
  13.   //重定向到內部鏈接 
  14.   r.GET("/internal", func(c *gin.Context) { 
  15.     c.Redirect(http.StatusMovedPermanently, "/home"
  16.   }) 
  17.  
  18.   r.GET("/home", func(c *gin.Context) { 
  19.     c.JSON(200, gin.H{"msg""這是首頁"}) 
  20.   }) 
  21.   r.Run(":8080"
  22.  
  23. /* 
  24. 重定向到外部鏈接,訪問:http://localhost:8080/test 
  25. 重定向到內部鏈接,訪問:http://localhost:8080/internal 
  26. */ 

從POST方法中完成HTTP重定向, 參考問題#444 https://github.com/gin-gonic/gin/issues/444

  1. r.POST("/test", func(c *gin.Context) { 
  2.   c.Redirect(http.StatusFound, "/foo"
  3. }) 

如果要產生一個路由重定向, 類似上面的內部重定向, 則使用 HandleContext方法, 像下面這樣使用:

  1. r.GET("/test", func(c *gin.Context) { 
  2.     c.Request.URL.Path = "/test2" 
  3.     r.HandleContext(c) 
  4. }) 
  5. r.GET("/test2", func(c *gin.Context) { 
  6.     c.JSON(200, gin.H{"hello""world"}) 
  7. }) 

自定義中間件

  1. package main 
  2.  
  3. import ( 
  4.   "github.com/gin-gonic/gin" 
  5.   "log" 
  6.   "time" 
  7.  
  8. //自定義日志中間件 
  9. func Logger() gin.HandlerFunc { 
  10.   return func(c *gin.Context) { 
  11.     t := time.Now() 
  12.  
  13.     // Set example variable 在gin上下文中設置鍵值對 
  14.     c.Set("example""12345"
  15.  
  16.     // before request 
  17.  
  18.     //Next方法只能用于中間件中,在當前中間件中, 從方法鏈執行掛起的處理器 
  19.     c.Next() 
  20.  
  21.     // after request  打印中間件執行耗時 
  22.     latency := time.Since(t) 
  23.     log.Print(latency) 
  24.  
  25.     // access the status we are sending  打印本中間件的狀態碼 
  26.     status := c.Writer.Status() 
  27.     log.Println(status) 
  28.   } 
  29.  
  30. func main() { 
  31.   r := gin.New() 
  32.   //使用該自定義中間件 
  33.   r.Use(Logger()) 
  34.   r.GET("/test", func(c *gin.Context) { 
  35.     example := c.MustGet("example").(string) //從上下文中獲取鍵值對 
  36.     // it would print: "12345" 
  37.     log.Println(example) 
  38.   }) 
  39.  
  40.   // Listen and serve on 0.0.0.0:8080 
  41.   r.Run(":8080"

使用基本認證BasicAuth()中間件

  1. package main 
  2.  
  3. import ( 
  4.   "github.com/gin-gonic/gin" 
  5.   "net/http" 
  6.  
  7. // simulate some private data 
  8. var secrets = gin.H{ 
  9.   "foo":    gin.H{"email""foo@bar.com""phone""123433"}, 
  10.   "austin": gin.H{"email""austin@example.com""phone""666"}, 
  11.   "lena":   gin.H{"email""lena@guapa.com""phone""523443"}, 
  12.  
  13. func main() { 
  14.   r := gin.Default() 
  15.  
  16.   // Group using gin.BasicAuth() middleware 
  17.   // gin.Accounts is a shortcut for map[string]string 
  18.   // 路由組authorized使用基本認證中間件, 參數為gin.Accounts,是一個map,鍵名是用戶名, 鍵值是密碼, 該中間件會將認證信息保存到cookie中 
  19.   authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ 
  20.     "foo":    "bar"
  21.     "austin""1234"
  22.     "lena":   "hello2"
  23.     "manu":   "4321"
  24.   })) 
  25.  
  26.   // /admin/secrets endpoint 
  27.   // hit "localhost:8080/admin/secrets 
  28.   authorized.GET("/secrets", func(c *gin.Context) { 
  29.     // get user, it was set by the BasicAuth middleware 
  30.     // 從cookie中獲取用戶認證信息, 鍵名為user 
  31.     user := c.MustGet(gin.AuthUserKey).(string) 
  32.     if secret, ok := secrets[user]; ok { 
  33.       c.JSON(http.StatusOK, gin.H{"user"user"secret": secret}) 
  34.     } else { 
  35.       c.JSON(http.StatusOK, gin.H{"user"user"secret""NO SECRET :("}) 
  36.     } 
  37.   }) 
  38.  
  39.   // Listen and serve on 0.0.0.0:8080 
  40.   r.Run(":8080"
  41. /* 
  42. 測試訪問:http://localhost:8080/admin/secrets 
  43. */ 

在中間件中使用協程Goroutines

在中間件或者控制器中啟動新協程時, 不能直接使用原來的Gin上下文, 必須使用一個只讀的上下文副本

  1. package main 
  2.  
  3. import ( 
  4.   "github.com/gin-gonic/gin" 
  5.   "log" 
  6.   "time" 
  7.  
  8. func main() { 
  9.   r := gin.Default() 
  10.  
  11.   r.GET("/long_async", func(c *gin.Context) { 
  12.     // create copy to be used inside the goroutine 
  13.     // 創建一個Gin上下文的副本, 準備在協程Goroutine中使用 
  14.     cCp := c.Copy() 
  15.     go func() { 
  16.       // simulate a long task with time.Sleep(). 5 seconds 
  17.       // 模擬長時間任務,這里是5秒 
  18.       time.Sleep(5 * time.Second
  19.  
  20.       // note that you are using the copied context "cCp", IMPORTANT 
  21.       // 在中間件或者控制器中啟動協程時, 不能直接使用原來的上下文, 必須使用一個只讀的上線文副本 
  22.       log.Println("Done! in path " + cCp.Request.URL.Path) 
  23.     }() 
  24.   }) 
  25.  
  26.   r.GET("/long_sync", func(c *gin.Context) { 
  27.     // simulate a long task with time.Sleep(). 5 seconds 
  28.     time.Sleep(5 * time.Second
  29.  
  30.     // since we are NOT using a goroutine, we do not have to copy the context 
  31.     // 沒有使用協程時, 可以直接使用Gin上下文 
  32.     log.Println("Done! in path " + c.Request.URL.Path) 
  33.   }) 
  34.  
  35.   // Listen and serve on 0.0.0.0:8080 
  36.   r.Run(":8080"
  37. /* 
  38. 模擬同步阻塞訪問:http://localhost:8080/long_sync 
  39. 模擬異步非阻塞訪問:http://localhost:8080/long_async 
  40. */ 

自定義HTTP配置

直接使用 http.ListenAndServe()方法:

  1. func main() { 
  2.   router := gin.Default() 
  3.   http.ListenAndServe(":8080", router) 

或者自定義HTTP配置

  1. func main() { 
  2.   router := gin.Default() 
  3.  
  4.   s := &http.Server{ 
  5.     Addr:           ":8080"
  6.     Handler:        router, 
  7.     ReadTimeout:    10 * time.Second
  8.     WriteTimeout:   10 * time.Second
  9.     MaxHeaderBytes: 1 << 20, 
  10.   } 
  11.   s.ListenAndServe() 

支持Let'sEncrypt證書加密處理HTTPS

下面是一行式的LetsEncrypt HTTPS服務

  1. package main 
  2.  
  3. import ( 
  4.   "log" 
  5.  
  6.   "github.com/gin-gonic/autotls" 
  7.   "github.com/gin-gonic/gin" 
  8.  
  9. func main() { 
  10.   r := gin.Default() 
  11.  
  12.   // Ping handler 
  13.   r.GET("/ping", func(c *gin.Context) { 
  14.     c.String(200, "pong"
  15.   }) 
  16.   //一行式LetsEncrypt證書, 處理https 
  17.   log.Fatal(autotls.Run(r, "example1.com""example2.com")) 

自定義自動證書管理器autocert manager實例代碼:

  1. package main 
  2.  
  3. import ( 
  4.   "log" 
  5.  
  6.   "github.com/gin-gonic/autotls" 
  7.   "github.com/gin-gonic/gin" 
  8.   "golang.org/x/crypto/acme/autocert" 
  9.  
  10. func main() { 
  11.   r := gin.Default() 
  12.  
  13.   // Ping handler 
  14.   r.GET("/ping", func(c *gin.Context) { 
  15.     c.String(200, "pong"
  16.   }) 
  17.  
  18.   m := autocert.Manager{ 
  19.     Prompt:     autocert.AcceptTOS, //Prompt指定一個回調函數有條件的接受證書機構CA的TOS服務, 使用AcceptTOS總是接受服務條款 
  20.     HostPolicy: autocert.HostWhitelist("example1.com""example2.com"),  //HostPolicy用于控制指定哪些域名, 管理器將檢索新證書 
  21.     Cache:      autocert.DirCache("/var/www/.cache"),  //緩存證書和其他狀態 
  22.   } 
  23.  
  24.   log.Fatal(autotls.RunWithManager(r, &m)) 

詳情參考autotls包

使用Gin運行多個服務

可以在主函數中使用協程Goroutine運行多個服務, 每個服務端口不同, 路由分組也不同. 請參考這個問題, 嘗試運行以下示例代碼:

  1. package main 
  2.  
  3. import ( 
  4.   "log" 
  5.   "net/http" 
  6.   "time" 
  7.  
  8.   "github.com/gin-gonic/gin" 
  9.   "golang.org/x/sync/errgroup" 
  10.  
  11. var ( 
  12.   g errgroup.Group 
  13.  
  14. func router01() http.Handler { 
  15.   e := gin.New() 
  16.   e.Use(gin.Recovery()) 
  17.   e.GET("/", func(c *gin.Context) { 
  18.     c.JSON( 
  19.       http.StatusOK, 
  20.       gin.H{ 
  21.         "code":  http.StatusOK, 
  22.         "error""Welcome server 01"
  23.       }, 
  24.     ) 
  25.   }) 
  26.  
  27.   return e 
  28.  
  29. func router02() http.Handler { 
  30.   e := gin.New() 
  31.   e.Use(gin.Recovery()) 
  32.   e.GET("/", func(c *gin.Context) { 
  33.     c.JSON( 
  34.       http.StatusOK, 
  35.       gin.H{ 
  36.         "code":  http.StatusOK, 
  37.         "error""Welcome server 02"
  38.       }, 
  39.     ) 
  40.   }) 
  41.  
  42.   return e 
  43.  
  44. func main() { 
  45.   server01 := &http.Server{ 
  46.     Addr:         ":8080"
  47.     Handler:      router01(), 
  48.     ReadTimeout:  5 * time.Second
  49.     WriteTimeout: 10 * time.Second
  50.   } 
  51.  
  52.   server02 := &http.Server{ 
  53.     Addr:         ":8081"
  54.     Handler:      router02(), 
  55.     ReadTimeout:  5 * time.Second
  56.     WriteTimeout: 10 * time.Second
  57.   } 
  58.  
  59.   g.Go(func() error { 
  60.     err := server01.ListenAndServe() 
  61.     if err != nil && err != http.ErrServerClosed { 
  62.       log.Fatal(err) 
  63.     } 
  64.     return err 
  65.   }) 
  66.  
  67.   g.Go(func() error { 
  68.     err := server02.ListenAndServe() 
  69.     if err != nil && err != http.ErrServerClosed { 
  70.       log.Fatal(err) 
  71.     } 
  72.     return err 
  73.   }) 
  74.  
  75.   if err := g.Wait(); err != nil { 
  76.     log.Fatal(err) 
  77.   } 
  78.  
  79. /* 
  80. 模擬訪問服務1: 
  81. curl http://localhost:8080/ 
  82. {"code":200,"error":"Welcome server 01"
  83.  
  84. 模擬訪問服務2: 
  85. curl http://localhost:8081/ 
  86. {"code":200,"error":"Welcome server 02"
  87. */ 

優雅的關閉和重啟服務

有一些方法可以優雅的關閉或者重啟服務, 比如不應該中斷活動的連接, 需要優雅等待服務完成后才執行關閉或重啟. 你可以使用第三方包來實現, 也可以使用內置的包自己實現優雅關閉或重啟.

使用第三方包

fvbock/endless 包, 可以實現Golang HTTP/HTTPS服務的零停機和優雅重啟(Golang版本至少1.3以上)

我們可以使用fvbock/endless 替代默認的 ListenAndServe方法, 更多詳情, 請參考問題#296.

  1. router := gin.Default() 
  2. router.GET("/", handler) 
  3. // [...] 
  4. endless.ListenAndServe(":4242", router) 

其他替代包:

  • manners: 一個優雅的Go HTTP服務, 可以優雅的關閉服務.
  • graceful: 優雅的Go包, 能夠優雅的關閉一個http.Handler服務
  • grace: 該包為Go服務實現優雅重啟, 零停機

手動實現

如果你使用Go1.8或者更高的版本, 你可能不需要使用這些庫. 可以考慮使用http.Server的內置方法Shutdown()來優雅關閉服務. 下面的示例描述了基本用法, 更多示例請參考這里

  1. // +build go1.8 
  2.  
  3. package main 
  4.  
  5. import ( 
  6.   "context" 
  7.   "log" 
  8.   "net/http" 
  9.   "os" 
  10.   "os/signal" 
  11.   "syscall" 
  12.   "time" 
  13.  
  14.   "github.com/gin-gonic/gin" 
  15.  
  16. func main() { 
  17.   router := gin.Default() 
  18.   router.GET("/", func(c *gin.Context) { 
  19.     time.Sleep(5 * time.Second
  20.     c.String(http.StatusOK, "Welcome Gin Server"
  21.   }) 
  22.  
  23.   srv := &http.Server{ 
  24.     Addr:    ":8080"
  25.     Handler: router, 
  26.   } 
  27.  
  28.   // Initializing the server in a goroutine so that 
  29.   // it won't block the graceful shutdown handling below 
  30.   // 用協程初始化一個服務, 它不會阻塞下面的優雅邏輯處理 
  31.   go func() { 
  32.     if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { 
  33.       log.Fatalf("listen: %s\n", err) 
  34.     } 
  35.   }() 
  36.  
  37.   // Wait for interrupt signal to gracefully shutdown the server with 
  38.   // a timeout of 5 seconds. 
  39.   //等待一個操作系統的中斷信號, 來優雅的關閉服務 
  40.   quit := make(chan os.Signal) 
  41.   // kill (no param) default send syscall.SIGTERM  //kill會發送終止信號 
  42.   // kill -2 is syscall.SIGINT  //發送強制進程結束信號 
  43.   // kill -9 is syscall.SIGKILL but can't be catch, so don't need add it  //發送SIGKILL信號給進程 
  44.   signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) 
  45.   <-quit //阻塞在這里,直到獲取到一個上面的信號 
  46.   log.Println("Shutting down server..."
  47.  
  48.   // The context is used to inform the server it has 5 seconds to finish 
  49.   // the request it is currently handling 
  50.   //這里使用context上下文包, 有5秒鐘的處理超時時間 
  51.   ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second
  52.   defer cancel() 
  53.   if err := srv.Shutdown(ctx); err != nil {  //利用內置Shutdown方法優雅關閉服務 
  54.     log.Fatal("Server forced to shutdown:", err) 
  55.   } 
  56.  
  57.   log.Println("Server exiting"

參考文檔

Gin官方倉庫:https://github.com/gin-gonic/gin

 

責任編輯:姜華 來源: 云原生云
相關推薦

2020-12-10 10:22:48

GinWeb中間件HTTPS

2020-11-25 09:18:15

Golang GinW

2020-12-02 11:18:28

Golang GinW

2020-11-25 09:10:39

Golang GinW

2016-11-11 21:00:46

中間件

2024-12-09 00:00:15

Gin框架中間件

2021-10-06 19:03:35

Go中間件Middleware

2020-11-23 10:48:39

Golang GinW

2024-01-05 08:17:53

FiberGolang路由

2023-05-08 08:09:26

路由元信息謂詞

2021-01-20 08:26:16

中間件技術spring

2025-02-08 11:49:42

2024-05-06 12:30:51

Go語言中間件

2020-12-03 09:28:05

Golang GinW

2011-05-24 15:10:48

2021-02-11 08:21:02

中間件開發CRUD

2018-02-01 10:19:22

中間件服務器系統

2018-07-29 12:27:30

云中間件云計算API

2020-01-07 08:00:52

ApacheHTTPHTTPS

2020-11-26 10:08:17

Golang GinW
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品免费视频一区二区 | 成人午夜av| 99精品免费在线观看 | www.788.com色淫免费 | 99精品视频在线观看 | 国产精品一区二区三区在线 | 欧美激情区 | 成人片免费看 | 天堂一区 | 久久香蕉精品视频 | 午夜手机在线视频 | 亚洲人成一区二区三区性色 | 91性高湖久久久久久久久_久久99 | 国产精品一区久久久 | 中文字幕国产精品 | 日韩免费| av在线视 | 日韩电影免费观看中文字幕 | 国产 日韩 欧美 在线 | 一区二区视频 | 成人久久18免费网站麻豆 | 天堂资源 | 国产精品视频免费播放 | 亚洲综合成人网 | 国产精品成人一区二区三区 | 日韩久久久久 | 成人在线免费视频 | 天天看天天摸天天操 | 日日日色 | 免费国产一区二区视频 | 中文字幕中文字幕 | 日本黄色片免费在线观看 | 国产91网站在线观看 | 毛片一区 | www.亚洲区| 二区在线视频 | 精品国产不卡一区二区三区 | 欧美黄色精品 | 国产午夜视频 | www.黄色片视频 | 成人av网站在线观看 |