这篇文章主要讲解了“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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。