温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Golang GinWeb框架之重定向/自定义中间件/认证/HTTPS支持/优雅重启等知识点总结

发布时间:2021-10-22 16:42:34 来源:亿速云 阅读:315 作者:iii 栏目:web开发

这篇文章主要讲解了“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支持/优雅重启等知识点总结这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI