自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Golang GinWeb框架8-重定向/自定義中間件/認(rèn)證/HTTPS支持/優(yōu)雅重啟等

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

[[356340]]

 簡(jiǎn)介

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

重定向

Gin返回一個(gè)HTTP重定向非常簡(jiǎn)單, 使用Redirect方法即可. 內(nèi)部和外部鏈接都支持.

  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.   //重定向到內(nèi)部鏈接 
  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. 重定向到內(nèi)部鏈接,訪問: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. }) 

如果要產(chǎn)生一個(gè)路由重定向, 類似上面的內(nèi)部重定向, 則使用 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上下文中設(shè)置鍵值對(duì) 
  14.     c.Set("example""12345"
  15.  
  16.     // before request 
  17.  
  18.     //Next方法只能用于中間件中,在當(dāng)前中間件中, 從方法鏈執(zhí)行掛起的處理器 
  19.     c.Next() 
  20.  
  21.     // after request  打印中間件執(zhí)行耗時(shí) 
  22.     latency := time.Since(t) 
  23.     log.Print(latency) 
  24.  
  25.     // access the status we are sending  打印本中間件的狀態(tài)碼 
  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) //從上下文中獲取鍵值對(duì) 
  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"

使用基本認(rèn)證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使用基本認(rèn)證中間件, 參數(shù)為gin.Accounts,是一個(gè)map,鍵名是用戶名, 鍵值是密碼, 該中間件會(huì)將認(rèn)證信息保存到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中獲取用戶認(rèn)證信息, 鍵名為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. 測(cè)試訪問:http://localhost:8080/admin/secrets 
  43. */ 

在中間件中使用協(xié)程Goroutines

在中間件或者控制器中啟動(dòng)新協(xié)程時(shí), 不能直接使用原來的Gin上下文, 必須使用一個(gè)只讀的上下文副本

  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.     // 創(chuàng)建一個(gè)Gin上下文的副本, 準(zhǔn)備在協(xié)程Goroutine中使用 
  14.     cCp := c.Copy() 
  15.     go func() { 
  16.       // simulate a long task with time.Sleep(). 5 seconds 
  17.       // 模擬長(zhǎng)時(shí)間任務(wù),這里是5秒 
  18.       time.Sleep(5 * time.Second
  19.  
  20.       // note that you are using the copied context "cCp", IMPORTANT 
  21.       // 在中間件或者控制器中啟動(dòng)協(xié)程時(shí), 不能直接使用原來的上下文, 必須使用一個(gè)只讀的上線文副本 
  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.     // 沒有使用協(xié)程時(shí), 可以直接使用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服務(wù)

  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")) 

自定義自動(dòng)證書管理器autocert manager實(shí)例代碼:

  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指定一個(gè)回調(diào)函數(shù)有條件的接受證書機(jī)構(gòu)CA的TOS服務(wù), 使用AcceptTOS總是接受服務(wù)條款 
  20.     HostPolicy: autocert.HostWhitelist("example1.com""example2.com"),  //HostPolicy用于控制指定哪些域名, 管理器將檢索新證書 
  21.     Cache:      autocert.DirCache("/var/www/.cache"),  //緩存證書和其他狀態(tài) 
  22.   } 
  23.  
  24.   log.Fatal(autotls.RunWithManager(r, &m)) 

詳情參考autotls包

使用Gin運(yùn)行多個(gè)服務(wù)

可以在主函數(shù)中使用協(xié)程Goroutine運(yùn)行多個(gè)服務(wù), 每個(gè)服務(wù)端口不同, 路由分組也不同. 請(qǐng)參考這個(gè)問題, 嘗試運(yùn)行以下示例代碼:

  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. 模擬訪問服務(wù)1: 
  81. curl http://localhost:8080/ 
  82. {"code":200,"error":"Welcome server 01"
  83.  
  84. 模擬訪問服務(wù)2: 
  85. curl http://localhost:8081/ 
  86. {"code":200,"error":"Welcome server 02"
  87. */ 

優(yōu)雅的關(guān)閉和重啟服務(wù)

有一些方法可以優(yōu)雅的關(guān)閉或者重啟服務(wù), 比如不應(yīng)該中斷活動(dòng)的連接, 需要優(yōu)雅等待服務(wù)完成后才執(zhí)行關(guān)閉或重啟. 你可以使用第三方包來實(shí)現(xiàn), 也可以使用內(nèi)置的包自己實(shí)現(xiàn)優(yōu)雅關(guān)閉或重啟.

使用第三方包

fvbock/endless 包, 可以實(shí)現(xiàn)Golang HTTP/HTTPS服務(wù)的零停機(jī)和優(yōu)雅重啟(Golang版本至少1.3以上)

我們可以使用fvbock/endless 替代默認(rèn)的 ListenAndServe方法, 更多詳情, 請(qǐng)參考問題#296.

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

其他替代包:

  • manners: 一個(gè)優(yōu)雅的Go HTTP服務(wù), 可以優(yōu)雅的關(guān)閉服務(wù).
  • graceful: 優(yōu)雅的Go包, 能夠優(yōu)雅的關(guān)閉一個(gè)http.Handler服務(wù)
  • grace: 該包為Go服務(wù)實(shí)現(xiàn)優(yōu)雅重啟, 零停機(jī)

手動(dòng)實(shí)現(xiàn)

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

  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.   // 用協(xié)程初始化一個(gè)服務(wù), 它不會(huì)阻塞下面的優(yōu)雅邏輯處理 
  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.   //等待一個(gè)操作系統(tǒng)的中斷信號(hào), 來優(yōu)雅的關(guān)閉服務(wù) 
  40.   quit := make(chan os.Signal) 
  41.   // kill (no param) default send syscall.SIGTERM  //kill會(huì)發(fā)送終止信號(hào) 
  42.   // kill -2 is syscall.SIGINT  //發(fā)送強(qiáng)制進(jìn)程結(jié)束信號(hào) 
  43.   // kill -9 is syscall.SIGKILL but can't be catch, so don't need add it  //發(fā)送SIGKILL信號(hào)給進(jìn)程 
  44.   signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) 
  45.   <-quit //阻塞在這里,直到獲取到一個(gè)上面的信號(hào) 
  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秒鐘的處理超時(shí)時(shí)間 
  51.   ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second
  52.   defer cancel() 
  53.   if err := srv.Shutdown(ctx); err != nil {  //利用內(nèi)置Shutdown方法優(yōu)雅關(guān)閉服務(wù) 
  54.     log.Fatal("Server forced to shutdown:", err) 
  55.   } 
  56.  
  57.   log.Println("Server exiting"

參考文檔

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

 

責(zé)任編輯:姜華 來源: 云原生云
相關(guān)推薦

2020-12-10 10:22:48

GinWeb中間件HTTPS

2020-11-25 09:18:15

Golang GinW

2016-11-11 21:00:46

中間件

2020-11-25 09:10:39

Golang GinW

2024-12-09 00:00:15

Gin框架中間件

2021-10-06 19:03:35

Go中間件Middleware

2020-12-02 11:18:28

Golang GinW

2024-01-05 08:17:53

FiberGolang路由

2023-05-08 08:09:26

路由元信息謂詞

2021-01-20 08:26:16

中間件技術(shù)spring

2020-11-23 10:48:39

Golang GinW

2025-02-08 11:49:42

2024-05-06 12:30:51

Go語言中間件

2021-02-11 08:21:02

中間件開發(fā)CRUD

2011-05-24 15:10:48

2018-07-29 12:27:30

云中間件云計(jì)算API

2018-02-01 10:19:22

中間件服務(wù)器系統(tǒng)

2020-01-07 08:00:52

ApacheHTTPHTTPS

2020-12-03 09:28:05

Golang GinW

2023-06-29 10:10:06

Rocket MQ消息中間件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)