Gin框架使用入门
Gin是一个使用Go语言编写的HTTP Web框架,它拥有极高的性能和简洁明快的语法,在Go语言开发社区中非常受欢迎。Gin的API简单易用,对初学者十分友好,而且提供了中文文档,容易上手。
路由中间件
Gin Web框架允许Web开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件。
中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
比如,如果访问一个网页的话,访问特定的路径都需要进行登录,此时就需要为所有路径的处理函数进行统一一个中间件,例如极简版抖音中的登陆需求。
Gin Web框架中的中间件必须是一个gin.HandlerFunc类型。
单独添加中间件
首先需要定义一个中间件函数。
func middleware(c *gin.Context) {
fmt.Println("xxx")
}
然后中间件函数就可以放在请求处理函数前。
r.GET("/feed/", middleware, controller.Feed)
这样,当用户向路由路径 /feed 发送GET请求时,会先进入middleware函数进行处理,然后再进入controller.Feed中响应GET请求。
如果想添加多个中间件,逻辑和单独单个添加一样。请求GET后面,可以添加任意多个HandlerFunc方法。
如r.GET("/feed/", middleware1, middleware2, controller.Feed)
这样GET请求 /feed 时的函数执行顺序就是 milleware1->middleware2->controller.Feed
中间件拦截
c.Abort()方法对中间件拦截,后续的HandlerFunc不会执行。即阻止调用后续的处理函数。
如r.GET("/feed/", middleware1, middleware2, controller.Feed)
如果在执行middleware2遇到c.Abort()方法时,则会停止调用controller.Feed,但会把middleware2函数继续执行完毕。如果想直接停止,则在c.Abort()后面接一个return就可以了。
中间件穿透
c.Next()可以理解为洋葱穿透。
c.Next() 之前的操作是在 Handler 执行之前就执行。c.Next() 之后的操作是在 Handler 执行之后再执行。
c.Next()之前的操作一般用来做验证处理,访问是否允许之类的。c.Next()之后的操作一般是用来做总结处理,比如格式化输出、响应结束时间,响应时长计算之类的。Next前后形成了其他语言中的请求中间件和响应中间件。
package main
func middleware1(c *gin.Context) {
fmt.Println("middleware1 ...in")
c.Next()
fmt.Println("middleware1 ...out")
}
func middleware2(c *gin.Context) {
fmt.Println("middleware2 ...in")
c.Next()
fmt.Println("middleware2 ...out")
}
func main() {
router := gin.Default()
router.GET("/", m1, func(c *gin.Context) {
fmt.Println("feed ...in")
c.String(200, "OK")
c.Next()
fmt.Println("feed ...out")
}, m2)
router.Run(":8080")
}
上述按序代码会输出
- middleware1 ...in
- feed ...in
- middleware2 ...in
- middleware2 ...out
- feed ...out
- middleware1 ...out
执行逻辑大概如图。
如果其中一个中间件响应了c.Abort(),后续中间件将不再执行,直接按照顺序走完所有的响应中间件。
全局中间件
c.Use()。可以使用Use去注册全局中间件,Use接收的参数也是多个HandlerFunc。方法将全局中间件连接到路由器,即通过Use()连接的中间件将被包括在每个请求的处理中。
跨中间件传递数据
使用Set设置一个key-value,在后续中间件中使用Get接收数据。value的类型是any类型,所有我们可以用它传任意类型,在接收的时候做好断言即可。
c.Set("name", "fengfeng") 设置键值对 name, _ := c.Get("name") 获取所对应的值
也可以用Keys[]来获取值。
name, _ := c.Keys["name"] 获取所对应的值。
路由分组
使用r.Group()将一系列的路由放到一个组下,统一管理。
apiRouter := r.Group("/douyin")
apiRouter.GET("/feed/", controller.Feed)
这样在Group分组后面添加Use,便可以指定哪些路由需要使用中间件。