欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

gin系列-中间件

程序员文章站 2022-07-09 19:48:12
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等 定义中间件 Gin中的中间件必须是一个gin.HandlerFunc类型 入门案例 注册中间件 在gin框架中 ......

gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等

定义中间件

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")
}

注册中间件

在gin框架中,可以为每个路由添加任意数量的中间件。

为全局路由注册

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系列-中间件

中间件注意事项

gin.default()

gin.default()默认使用了logger和recovery中间件,其中:logger中间件将日志写入gin.defaultwriter,即使配置了gin_mode=release。recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。如果不想使用上面两个默认的中间件,可以使用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系列-中间件

gin中间件中使用goroutine

当在中间件或handler中启动新的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")
}