您好,登錄后才能下訂單哦!
這篇文章主要講解了“Golang GinWeb框架之重定向/自定義中間件/認證/HTTPS支持/優雅重啟等知識點總結”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Golang GinWeb框架之重定向/自定義中間件/認證/HTTPS支持/優雅重啟等知識點總結”吧!
重定向
Gin返回一個HTTP重定向非常簡單, 使用Redirect方法即可. 內部和外部鏈接都支持.
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { r := gin.Default() r.GET("/test", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "http://www.google.com/") //重定向到外部鏈接 }) //重定向到內部鏈接 r.GET("/internal", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "/home") }) r.GET("/home", func(c *gin.Context) { c.JSON(200, gin.H{"msg": "這是首頁"}) }) r.Run(":8080") } /* 重定向到外部鏈接,訪問:http://localhost:8080/test 重定向到內部鏈接,訪問:http://localhost:8080/internal */
從POST方法中完成HTTP重定向, 參考問題#444 https://github.com/gin-gonic/gin/issues/444
r.POST("/test", func(c *gin.Context) { c.Redirect(http.StatusFound, "/foo") })
如果要產生一個路由重定向, 類似上面的內部重定向, 則使用 HandleContext方法, 像下面這樣使用:
r.GET("/test", func(c *gin.Context) { c.Request.URL.Path = "/test2" r.HandleContext(c) }) r.GET("/test2", func(c *gin.Context) { c.JSON(200, gin.H{"hello": "world"}) })
自定義中間件
package main import ( "github.com/gin-gonic/gin" "log" "time" ) //自定義日志中間件 func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // Set example variable 在gin上下文中設置鍵值對 c.Set("example", "12345") // before request //Next方法只能用于中間件中,在當前中間件中, 從方法鏈執行掛起的處理器 c.Next() // after request 打印中間件執行耗時 latency := time.Since(t) log.Print(latency) // access the status we are sending 打印本中間件的狀態碼 status := c.Writer.Status() log.Println(status) } } func main() { r := gin.New() //使用該自定義中間件 r.Use(Logger()) r.GET("/test", func(c *gin.Context) { example := c.MustGet("example").(string) //從上下文中獲取鍵值對 // it would print: "12345" log.Println(example) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") }
使用基本認證BasicAuth()中間件
package main import ( "github.com/gin-gonic/gin" "net/http" ) // simulate some private data var secrets = gin.H{ "foo": gin.H{"email": "foo@bar.com", "phone": "123433"}, "austin": gin.H{"email": "austin@example.com", "phone": "666"}, "lena": gin.H{"email": "lena@guapa.com", "phone": "523443"}, } func main() { r := gin.Default() // Group using gin.BasicAuth() middleware // gin.Accounts is a shortcut for map[string]string // 路由組authorized使用基本認證中間件, 參數為gin.Accounts,是一個map,鍵名是用戶名, 鍵值是密碼, 該中間件會將認證信息保存到cookie中 authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ "foo": "bar", "austin": "1234", "lena": "hello2", "manu": "4321", })) // /admin/secrets endpoint // hit "localhost:8080/admin/secrets authorized.GET("/secrets", func(c *gin.Context) { // get user, it was set by the BasicAuth middleware // 從cookie中獲取用戶認證信息, 鍵名為user user := c.MustGet(gin.AuthUserKey).(string) if secret, ok := secrets[user]; ok { c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret}) } else { c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("}) } }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } /* 測試訪問:http://localhost:8080/admin/secrets */
在中間件中使用協程Goroutines
在中間件或者控制器中啟動新協程時, 不能直接使用原來的Gin上下文, 必須使用一個只讀的上下文副本
package main import ( "github.com/gin-gonic/gin" "log" "time" ) func main() { r := gin.Default() r.GET("/long_async", func(c *gin.Context) { // create copy to be used inside the goroutine // 創建一個Gin上下文的副本, 準備在協程Goroutine中使用 cCp := c.Copy() go func() { // simulate a long task with time.Sleep(). 5 seconds // 模擬長時間任務,這里是5秒 time.Sleep(5 * time.Second) // note that you are using the copied context "cCp", IMPORTANT // 在中間件或者控制器中啟動協程時, 不能直接使用原來的上下文, 必須使用一個只讀的上線文副本 log.Println("Done! in path " + cCp.Request.URL.Path) }() }) r.GET("/long_sync", func(c *gin.Context) { // simulate a long task with time.Sleep(). 5 seconds time.Sleep(5 * time.Second) // since we are NOT using a goroutine, we do not have to copy the context // 沒有使用協程時, 可以直接使用Gin上下文 log.Println("Done! in path " + c.Request.URL.Path) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } /* 模擬同步阻塞訪問:http://localhost:8080/long_sync 模擬異步非阻塞訪問:http://localhost:8080/long_async */
自定義HTTP配置
直接使用 http.ListenAndServe()方法:
func main() { router := gin.Default() http.ListenAndServe(":8080", router) }
或者自定義HTTP配置
func main() { router := gin.Default() s := &http.Server{ Addr: ":8080", Handler: router, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } s.ListenAndServe() }
支持Let'sEncrypt證書加密處理HTTPS
下面是一行式的LetsEncrypt HTTPS服務
package main import ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) //一行式LetsEncrypt證書, 處理https log.Fatal(autotls.Run(r, "example1.com", "example2.com")) }
自定義自動證書管理器autocert manager實例代碼:
package main import ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" "golang.org/x/crypto/acme/autocert" ) func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) m := autocert.Manager{ Prompt: autocert.AcceptTOS, //Prompt指定一個回調函數有條件的接受證書機構CA的TOS服務, 使用AcceptTOS總是接受服務條款 HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"), //HostPolicy用于控制指定哪些域名, 管理器將檢索新證書 Cache: autocert.DirCache("/var/www/.cache"), //緩存證書和其他狀態 } log.Fatal(autotls.RunWithManager(r, &m)) }
詳情參考autotls包
使用Gin運行多個服務
可以在主函數中使用協程Goroutine運行多個服務, 每個服務端口不同, 路由分組也不同. 請參考這個問題, 嘗試運行以下示例代碼:
package main import ( "log" "net/http" "time" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" ) var ( g errgroup.Group ) func router01() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 01", }, ) }) return e } func router02() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 02", }, ) }) return e } func main() { server01 := &http.Server{ Addr: ":8080", Handler: router01(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } server02 := &http.Server{ Addr: ":8081", Handler: router02(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } g.Go(func() error { err := server01.ListenAndServe() if err != nil && err != http.ErrServerClosed { log.Fatal(err) } return err }) g.Go(func() error { err := server02.ListenAndServe() if err != nil && err != http.ErrServerClosed { log.Fatal(err) } return err }) if err := g.Wait(); err != nil { log.Fatal(err) } } /* 模擬訪問服務1: curl http://localhost:8080/ {"code":200,"error":"Welcome server 01"} 模擬訪問服務2: curl http://localhost:8081/ {"code":200,"error":"Welcome server 02"} */
優雅的關閉和重啟服務
有一些方法可以優雅的關閉或者重啟服務, 比如不應該中斷活動的連接, 需要優雅等待服務完成后才執行關閉或重啟. 你可以使用第三方包來實現, 也可以使用內置的包自己實現優雅關閉或重啟.
使用第三方包
fvbock/endless 包, 可以實現Golang HTTP/HTTPS服務的零停機和優雅重啟(Golang版本至少1.3以上)
我們可以使用fvbock/endless 替代默認的 ListenAndServe方法, 更多詳情, 請參考問題#296.
router := gin.Default() router.GET("/", handler) // [...] endless.ListenAndServe(":4242", router)
其他替代包:
manners: 一個優雅的Go HTTP服務, 可以優雅的關閉服務.
graceful: 優雅的Go包, 能夠優雅的關閉一個http.Handler服務
grace: 該包為Go服務實現優雅重啟, 零停機
手動實現
如果你使用Go1.8或者更高的版本, 你可能不需要使用這些庫. 可以考慮使用http.Server的內置方法Shutdown()來優雅關閉服務. 下面的示例描述了基本用法, 更多示例請參考這里
// +build go1.8 package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin" ) func main() { router := gin.Default() router.GET("/", func(c *gin.Context) { time.Sleep(5 * time.Second) c.String(http.StatusOK, "Welcome Gin Server") }) srv := &http.Server{ Addr: ":8080", Handler: router, } // Initializing the server in a goroutine so that // it won't block the graceful shutdown handling below // 用協程初始化一個服務, 它不會阻塞下面的優雅邏輯處理 go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }() // Wait for interrupt signal to gracefully shutdown the server with // a timeout of 5 seconds. //等待一個操作系統的中斷信號, 來優雅的關閉服務 quit := make(chan os.Signal) // kill (no param) default send syscall.SIGTERM //kill會發送終止信號 // kill -2 is syscall.SIGINT //發送強制進程結束信號 // kill -9 is syscall.SIGKILL but can't be catch, so don't need add it //發送SIGKILL信號給進程 signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit //阻塞在這里,直到獲取到一個上面的信號 log.Println("Shutting down server...") // The context is used to inform the server it has 5 seconds to finish // the request it is currently handling //這里使用context上下文包, 有5秒鐘的處理超時時間 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { //利用內置Shutdown方法優雅關閉服務 log.Fatal("Server forced to shutdown:", err) } log.Println("Server exiting") }
感謝各位的閱讀,以上就是“Golang GinWeb框架之重定向/自定義中間件/認證/HTTPS支持/優雅重啟等知識點總結”的內容了,經過本文的學習后,相信大家對Golang GinWeb框架之重定向/自定義中間件/認證/HTTPS支持/優雅重啟等知識點總結這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。