当前位置: 移动技术网 > IT编程>脚本编程>Go语言 > gin系列-中间件

gin系列-中间件

2020年04月22日  | 移动技术网IT编程  | 我要评论

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.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中间件中使用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")
}

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网