Ginフレームワークを使用すると、開発者はリクエストの処理中に独自のフック関数を追加できます。このフック関数はミドルウェアと呼ばれます。ミドルウェアは、ログイン認証、権限検証、データページング、ロギング、時間のかかる統計などの一般的なビジネスロジックの処理に適しています。
ミドルウェアを定義する
Ginのミドルウェアはgin.HandlerFuncタイプである必要があります
エントリーケース
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
}
func main() {
r := gin.Default()
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
r.GET("/index",m1,indexHandler)
//r.GET("/index", func(c *gin.Context) {
// c.JSON(http.StatusOK, gin.H{
// "msg": "indx",
// })
//})
r.Run(":9090")
}
[GIN-debug] Listening and serving HTTP on :9090
m1 in ....
index in ...
[GIN] 2020/04/21 - 15:21:31 |?[97;42m 200 ?[0m| 998.3µs | 127.0.0.1 |?[97;44m GET ?[0m "/index"
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
//输出
// m1 in ....
//index in ...
//cost:%v
// 996.8µs
}
func main() {
r := gin.Default()
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
r.GET("/index",m1,indexHandler) //先执行m1函数再执行indexHandler函数
//r.GET("/index", func(c *gin.Context) {
// c.JSON(http.StatusOK, gin.H{
// "msg": "indx",
// })
//})
r.Run(":9090")
}
ミドルウェアを登録する
ジンフレームワークでは、ルートごとにミドルウェアをいくつでも追加できます。
グローバルルーティングに登録する
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
//输出
// [GIN-debug] Listening and serving HTTP on :9090
//m1 in ....
//m2 in ....
//index in ...
//m2 out
//cost:%v
// 997.3µs
//m1 out
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
c.Next() //调用后续的处理函数
fmt.Println("m2 out")
}
func main() {
r := gin.Default()
r.Use(m1,m2) //全局注册中间件函数m1,m2 洋葱模型 类似递归调用
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
//r.GET("/index",m1,indexHandler) //先执行m1函数再执行indexHandler函数
r.GET("/index",indexHandler)
r.GET("/shop", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.GET("/user", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.Run(":9090")
}
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
//输出
// [GIN-debug] Listening and serving HTTP on :9090
//m1 in ....
//m2 in ....
//m2 out
//cost:%v
// 997.8µs
//m1 out
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
//c.Next() //调用后续的处理函数
c.Abort() //阻止后续调用
//return //return 立即结束m2函数
//m1 in ....
//m2 in ....
//cost:%v
// 0s
//m1 out
fmt.Println("m2 out")
}
//func authMiddleware(c *gin.Context) { //通常写成闭包
// //是否登陆的判断
// //if 是登陆用户
// //c.Next()
// //else
// //c.Abort()
//}
func authMiddleware(doCheck bool)gin.HandlerFunc { //开关注册
//连接数据库
//或着其他准备工作
return func(c *gin.Context) {
if doCheck {
//是否登陆的判断
//if 是登陆用户
//c.Next()
//else
//c.Abort()
} else {
c.Next()
}
}
}
func main() {
r := gin.Default()
r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2 洋葱模型 类似递归调用
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
//r.GET("/index",m1,indexHandler) //先执行m1函数再执行indexHandler函数
r.GET("/index",indexHandler)
r.GET("/shop", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.GET("/user", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.Run(":9090")
}
ルートを個別に登録する
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}
func main() {
r := gin.Default()
r.GET("/user", m1, func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
//m1 in ....
//cost:%v
// 0s
//m1 out
r.Run(":9090")
}
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
c.JSON(http.StatusOK, gin.H{
"msg": "indx",
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
//c.Next() //调用后续的处理函数
c.Abort() //阻止后续调用
//return //return 立即结束m2函数
//m1 in ....
//m2 in ....
//cost:%v
// 0s
//m1 out
fmt.Println("m2 out")
}
func main() {
r := gin.Default()
r.GET("/user", m1,m2, func(c *gin.Context) { //可以单独多个路由
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
//[GIN-debug] Listening and serving HTTP on :9090
//m1 in ....
//m2 in ....
//m2 out
//cost:%v
// 0s
//m1 out
r.Run(":9090")
}
ルーティンググループのミドルウェアを登録する
func main() {
//路由组注册中间件方法1:
xxGroup := r.Group("/xx", authMiddleware(true))
{
xxGroup.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
})
}
//路由组注册中间件方法2:
xx2Group := r.Group("/xx")
xx2Group.Use(authMiddleware(true))
{
xxGroup.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
})
}
r.Run(":9090")
}
ミドルウェア全体の値にアクセスする
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
name, ok := c.Get("name") //从上下文中取值,跨中间件存取值
if !ok {
name = "匿名用户"
}
c.JSON(http.StatusOK, gin.H{
"msg": name,
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
c.Set("name","zisefeizhu") //在上下文中设置c的值
fmt.Println("m2 out")
}
func authMiddleware(doCheck bool)gin.HandlerFunc { //开关注册
//连接数据库
//或着其他准备工作
return func(c *gin.Context) {
if doCheck {
//是否登陆的判断
//if 是登陆用户
c.Next()
//else
//c.Abort()
} else {
c.Next()
}
}
}
func main() {
r := gin.Default()
r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2 洋葱模型 类似递归调用
//GET(relativePath string, handlers ...HandlerFunc) IRoutes
//r.GET("/index",m1,indexHandler) //先执行m1函数再执行indexHandler函数
r.GET("/index",indexHandler)
r.Run(":9090")
}
ミドルウェアの考慮事項
gin.Default()
gin.Default()は、デフォルトでLogger and Recoveryミドルウェアを使用します。Loggerミドルウェアは、GIN_MODE = releaseが構成されている場合でも、ログをgin.DefaultWriterに書き込みます。回復ミドルウェアはパニックを回復します。パニックが発生した場合、500応答コードが書き込まれます。上記の2つのデフォルトミドルウェアを使用したくない場合は、gin.New()を使用して、デフォルトミドルウェアなしで新しいルートを作成できます。
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func indexHandler(c *gin.Context) {
fmt.Println("index in ...")
name, ok := c.Get("name") //从上下文中取值,跨中间件存取值
if !ok {
name = "匿名用户"
}
c.JSON(http.StatusOK, gin.H{
"msg": name,
})
}
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}
func m2(c *gin.Context) {
fmt.Println("m2 in ....")
c.Set("name","zisefeizhu") //在上下文中设置c的值
fmt.Println("m2 out")
}
func authMiddleware(doCheck bool)gin.HandlerFunc { //开关注册
//连接数据库
//或着其他准备工作
return func(c *gin.Context) {
if doCheck {
//是否登陆的判断
//if 是登陆用户
c.Next()
//else
//c.Abort()
} else {
c.Next()
}
}
}
func main() {
//r := gin.Default() //默认使用Logger()和Recovery()中间件
r := gin.New()
r.Use(m1,m2,authMiddleware(true)) //全局注册中间件函数m1,m2 洋葱模型 类似递归调用
r.GET("/index",indexHandler)
r.GET("/shop", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.GET("/user", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "index",
})
})
r.Run(":9090")
}
[GIN-debug] Listening and serving HTTP on :9090
m1 in ....
m2 in ....
m2 out
index in ...
cost:%v
1.0137ms
m1 out
ginミドルウェアでgoroutineを使用する
ミドルウェアまたはハンドラーで新しいgoroutineを開始する場合、元のコンテキスト(c * gin.Context)は使用できず、その読み取り専用コピー(c.Copy())を使用する必要があります。
//定义一个中间件:统计耗时
func m1(c *gin.Context) {
fmt.Println("m1 in ....")
//计时
start := time.Now()
go funcXX(c.Copy()) //在funcXX中只能使用c的拷贝
c.Next() //调用后续的处理函数 执行indexHandler函数
//c.Abort() //阻止调用后续的处理函数
cost := time.Since(start)
fmt.Println("cost:%v\n", cost)
fmt.Println("m1 out")
}