小白教程
所有教程
关于
Search
172.71.254.121
172.71.254.121
参数设置
贡献
退出
操作
编辑
移动
保护
信息
历史
删除
查看“Golang Gin 中间件使用”的源代码
本页内容
上一节:
Golang_Gin_设置不同类型的响应返回值
下一节:
Golang_Gin_日志
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
[[分类:Golang Gin Web 框架教程]] == 什么是中间件<ref>https://zhuanlan.zhihu.com/p/507085115</ref> == 中间件是一个十分宽泛的概念,在不同领域表示不同的含义,其中在bs/cs软件编程框架中,中间件可以理解为一些用于解耦业务和非业务代码的钩子函数,这些函数可以适用于所有或者部分请求。 中间件的原理和钩子函数类似,在框架层面,程序运行到某个阶段自动执行预设值的函数,运行完后再回到跳出的那个阶段继续执行原函数。 在bs/cs开发中,为了在主体函数前后执行一些通用操作,常见的写法会预设一些钩子比如beforeXxxFunc、afterXxxFunc,但这毕竟只有两个函数并且是针对全局请求,想要实现部分钩子函数针对某些请求就得做一些额外的业务外的操作来达到目的。gin框架的中间件就解决了这些痛点。 <sample title="" desc=""> func main() { // 新建一个没有任何默认中间件的路由 r := gin.New() // 全局中间件 // Logger 中间件将日志写入 gin.DefaultWriter,即使你将 GIN_MODE 设置为 release。 // By default gin.DefaultWriter = os.Stdout r.Use(gin.Logger()) // Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500。 r.Use(gin.Recovery()) // 你可以为每个路由添加任意数量的中间件。 r.GET("/benchmark", MyBenchLogger(), benchEndpoint) // 认证路由组 // authorized := r.Group("/", AuthRequired()) // 和使用以下两行代码的效果完全一样: authorized := r.Group("/") // 路由组中间件! 在此例中,我们在 "authorized" 路由组中使用自定义创建的 // AuthRequired() 中间件 authorized.Use(AuthRequired()) { authorized.POST("/login", loginEndpoint) authorized.POST("/submit", submitEndpoint) authorized.POST("/read", readEndpoint) // 嵌套路由组 testing := authorized.Group("testing") testing.GET("/analytics", analyticsEndpoint) } // 监听并在 0.0.0.0:8080 上启动服务 r.Run(":8080") } </sample> == 自定义中间件 == <sample title="" desc=""> func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // 设置 example 变量 c.Set("example", "12345") // 请求前 c.Next() // 请求后 latency := time.Since(t) log.Print(latency) // 获取发送的 status 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) // 打印:"12345" log.Println(example) }) // 监听并在 0.0.0.0:8080 上启动服务 r.Run(":8080") } </sample> == BasicAuth 中间件 == 当我们开发了一个小工具没有开发权限系统的时候可以使用 HTTP Basic Auth 简单实现下权限校验。 <sample title="" desc=""> // 模拟一些私人数据 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() // 路由组使用 gin.BasicAuth() 中间件 // gin.Accounts 是 map[string]string 的一种快捷方式 authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ "foo": "bar", "austin": "1234", "lena": "hello2", "manu": "4321", })) // /admin/secrets 端点 // 触发 "localhost:8080/admin/secrets authorized.GET("/secrets", func(c *gin.Context) { // 获取用户,它是由 BasicAuth 中间件设置的 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 :("}) } }) // 监听并在 0.0.0.0:8080 上启动服务 r.Run(":8080") } </sample> == 在中间件中使用 Goroutine == 当在中间件或 handler 中启动新的 Goroutine 时,不能使用原始的上下文,必须使用只读副本。 <sample title="" desc=""> func main() { r := gin.Default() r.GET("/long_async", func(c *gin.Context) { // 创建在 goroutine 中使用的副本 cCp := c.Copy() go func() { // 用 time.Sleep() 模拟一个长任务。 time.Sleep(5 * time.Second) // 请注意您使用的是复制的上下文 "cCp",这一点很重要 log.Println("Done! in path " + cCp.Request.URL.Path) }() }) r.GET("/long_sync", func(c *gin.Context) { // 用 time.Sleep() 模拟一个长任务。 time.Sleep(5 * time.Second) // 因为没有使用 goroutine,不需要拷贝上下文 log.Println("Done! in path " + c.Request.URL.Path) }) // 监听并在 0.0.0.0:8080 上启动服务 r.Run(":8080") } </sample>
返回至“
Golang Gin 中间件使用
”。
上一节:
Golang_Gin_设置不同类型的响应返回值
下一节:
Golang_Gin_日志