[ go 与 golang | 青训营笔记]
这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天, 在学习了go的相关基础知识以后,可以说是初步的了解了go,接下来,我们将步入全新的环节,今天我们学习go的一个常用web框架gin
8. 中间件
Gin中的中间件必须是一个gin.HandlerFunc类型
单独注册中间件
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func indexHandler(c *gin.Context) {
fmt.Println("index.....")
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
}
//定义一个中间件
func m1(c *gin.Context) {
fmt.Println("m1 in.........")
}
func main() {
r := gin.Default()
//m1处于indexHandler函数的前面,请求来之后,先走m1,再走index
r.GET("/index", m1, indexHandler)
_ = r.Run()
}
多个中间件
router.GET,后面可以跟很多HandlerFunc方法,这些方法其实都可以叫中间件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func m1(c *gin.Context) {
fmt.Println("m1 ...in")
}
func m2(c *gin.Context) {
fmt.Println("m2 ...in")
}
func main() {
router := gin.Default()
router.GET("/", m1, func(c *gin.Context) {
fmt.Println("index ...")
c.JSON(200, gin.H{"msg": "响应数据"})
}, m2)
router.Run(":8080")
}
/*
m1 ...in
index ...
m2 ...in
*/
中间件拦截响应
c.Abort()拦截,后续的HandlerFunc就不会执行了
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func m1(c *gin.Context) {
fmt.Println("m1 ...in")
c.JSON(200, gin.H{"msg": "第一个中间件拦截了"})
c.Abort()
}
func m2(c *gin.Context) {
fmt.Println("m2 ...in")
}
func main() {
router := gin.Default()
router.GET("/", m1, func(c *gin.Context) {
fmt.Println("index ...")
c.JSON(200, gin.H{"msg": "响应数据"})
}, m2)
router.Run(":8080")
}
中间件放行
c.Next(),Next前后形成了其他语言中的请求中间件和响应中间件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func m1(c *gin.Context) {
fmt.Println("m1 ...in")
c.Next()
fmt.Println("m1 ...out")
}
func m2(c *gin.Context) {
fmt.Println("m2 ...in")
c.Next()
fmt.Println("m2 ...out")
}
func main() {
router := gin.Default()
router.GET("/", m1, func(c *gin.Context) {
fmt.Println("index ...in")
c.JSON(200, gin.H{"msg": "响应数据"})
c.Next()
fmt.Println("index ...out")
}, m2)
router.Run(":8080")
}
/*
m1 ...in
index ...in
m2 ...in
m2 ...out
index ...out
m1 ...out
*/
如果其中一个中间件响应了c.Abort(),后续中间件将不再执行,直接按照顺序走完所有的响应中间件
全局注册中间件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func m10(c *gin.Context) {
fmt.Println("m1 ...in")
c.Next()
fmt.Println("m1 ...out")
}
func main() {
router := gin.Default()
router.Use(m10)
router.GET("/", func(c *gin.Context) {
fmt.Println("index ...in")
c.JSON(200, gin.H{"msg": "index"})
c.Next()
fmt.Println("index ...out")
})
router.Run(":8080")
}
使用Use去注册全局中间件,Use接收的参数也是多个HandlerFunc
中间件传递数据
使用Set设置一个key-value,
在后续中间件中使用Get接收数据
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func m10(c *gin.Context) {
fmt.Println("m1 ...in")
c.Set("name", "fengfeng")
}
func main() {
router := gin.Default()
router.Use(m10)
router.GET("/", func(c *gin.Context) {
fmt.Println("index ...in")
name, _ := c.Get("name")
fmt.Println(name)
c.JSON(200, gin.H{"msg": "index"})
})
router.Run(":8080")
}
value的类型是any类型,所有我们可以用它传任意类型,在接收的时候做好断言即可
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
type User struct {
Name string
Age int
}
func m10(c *gin.Context) {
fmt.Println("m1 ...in")
c.Set("name", User{"ranran", 21})
c.Next()
fmt.Println("m1 ...out")
}
func main() {
router := gin.Default()
router.Use(m10)
router.GET("/", func(c *gin.Context) {
fmt.Println("index ...in")
name, _ := c.Get("name")
user := name.(User)
fmt.Println(user.Name, user.Age)
c.JSON(200, gin.H{"msg": "index"})
})
router.Run(":8080")
}
路由分组
将一系列的路由放到一个组下,统一管理
例如,以下的路由前面统一加上api的前缀
package main
import "github.com/gin-gonic/gin"
func main() {
router := gin.Default()
r := router.Group("/api")
r.GET("/index", func(c *gin.Context) {
c.String(200, "index")
})
r.GET("/home", func(c *gin.Context) {
c.String(200, "home")
})
router.Run(":8080")
}
路由分组注册中间件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func middle(c *gin.Context) {
fmt.Println("middle ...in")
}
func main() {
router := gin.Default()
r := router.Group("/api").Use(middle) // 可以链式,也可以直接r.Use(middle)
r.GET("/index", func(c *gin.Context) {
c.String(200, "index")
})
r.GET("/home", func(c *gin.Context) {
c.String(200, "home")
})
router.Run(":8080")
}
这样写我们就可以指定哪一些分组下可以使用中间件了
当然,中间件还有一种写法,就是使用函数加括号的形式
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func middle(c *gin.Context) {
fmt.Println("middle ...in")
}
func middle1() gin.HandlerFunc {
// 这里的代码是程序一开始就会执行
return func(c *gin.Context) {
// 这里是请求来了才会执行
fmt.Println("middle1 ...inin")
}
}
func main() {
router := gin.Default()
r := router.Group("/api").Use(middle, middle1())
r.GET("/index", func(c *gin.Context) {
c.String(200, "index")
})
r.GET("/home", func(c *gin.Context) {
c.String(200, "home")
})
router.Run(":8080")
}
gin.Default
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
gin.Default()默认使用了Logger和Recovery中间件,其中:
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。 Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。 如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由。
使用gin.New,如果不指定日志,那么在控制台中就不会有日志显示