Gin框架中的中间件

本文详细介绍了中间件的概念,以及在Gin框架中的使用,包括中间件的注册、全局使用、流程控制和内置中间件。重点展示了如何在Gin中实现权限校验、跨域处理和使用内置的Recovery和Logger中间件。
摘要由CSDN通过智能技术生成

什么是中间件

中间件(middleware)是一种独立的组件或模块,通常是一个函数或一组函数,常被用于处理请求或事件的过程中

中间件常用来实现一些通用的功能,如日志记录、权限校验、数据加工等

简单理解,中间件就是一面墙,立在函数的前面,每次调用这个函数前都要经过中间件。最容易想到的应用场景就是权限校验,用户不登陆就无法发布文章等等

Gin中的中间件

Gin框架中的中间件是一个gin.HandlerFunc类型,可以为每个路由添加任意数量的中间件

// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
	return group.handle(http.MethodGet, relativePath, handlers)
}

在源码中可以看到后面的参数为...HandlerFunc,是一个可变长度的HandlerFunc类型

配置路由的时候在回调函数前加上一个HandlerFunc类型的函数,就完成了中间件的注册

// 简单的中间件实现
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func test(c *gin.Context) {
	fmt.Println("test")
	c.JSON(200, gin.H{
		"message": "Test",
	})
}

func m1(c *gin.Context) {
	fmt.Println("m1......")
}

func main() {
	router := gin.Default()
	router.GET("/test", m1, test)

	router.Run()
}
// m1......
// test

访问localhost:8080后,控制台会依次打印

m1......

test

在执行路由处理函数test之前,先经过了m1中间件,这就是中间件最简单的使用

除了给路由单独注册中间件,也可以使用use()函数全局注册

// Use attaches a global middleware to the router. i.e. the middleware attached through Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
	engine.RouterGroup.Use(middleware...)
	engine.rebuild404Handlers()
	engine.rebuild405Handlers()
	return engine
}
// 简单的全局注册中间件
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func test(c *gin.Context) {
	fmt.Println("test")
	c.JSON(200, gin.H{
		"message": "Test",
	})
}

func index(c *gin.Context) {
	fmt.Println("index")
	c.JSON(200, gin.H{
		"message": "Index",
	})
}

func m1(c *gin.Context) {
	fmt.Println("m1......")
}

func main() {
	router := gin.Default()
	// 全局注册m1中间件
	router.Use(m1)
	router.GET("/test", test)
	router.GET("/index", index)
	
	router.Run()
}

router.use()就可以实现全局注册,每一个路由都注册了此中间件

还可以给路由组注册

// 写法1
testGroup := router.Group("/test", m1) 
{
    testGroup.GET("/test1", func(c *gin.Context) {...})
    ...
}
// 写法2
testGroup := router.Group("/test")
testGroup.Use(m1)
{
	testGroup.GET("/test1", func(c *gin.Context) {...})
	...
}
流程控制 

单纯的打印文字到控制台上没有意义,可以结合流程控制语句实现一些功能

比如写一个Cors跨域中间件,这里只是举一个中间件的使用例子,不再介绍关于跨域相关内容,感兴趣可以查看:跨源资源共享(CORS) - HTTP | MDN (mozilla.org)

// Cors 跨域处理
func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 允许所有的域名进行跨域请求
		c.Header("Access-Control-Allow-Origin", "*")
		// 允许跨域的请求头
		c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
		// 允许跨域请求的方法
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
		// 允许跨域请求的响应头
		c.Header("Access-Control-Expose-Headers",
			"Content-Length, Access-Control-Allow-Origin, "+
				"Access-Control-Allow-Headers, Content-Type")
		// 允许跨域请求携带cookie
		c.Header("Access-Control-Allow-Credentials", "true")
		method := c.Request.Method
		// OPTIONS方法用于获取目的资源所支持的通信选项
		if method == "OPTIONS" {
			// 如果是OPTIONS请求,直接返回空响应
			c.AbortWithStatus(http.StatusNoContent)
		}
		// 处理请求
		c.Next()
	}
}

在gin框架中,中间件流程控制函数包括:

1. c.Next(): 调用该函数会将控制权交给下一个中间件函数,如果没有下一个中间件函数,则将控制权交给处理请求的路由处理函数

2. c.Abort(): 调用该函数会立即终止当前中间件函数的执行,并且不会再调用后续的中间件函数或路由处理函数

3. c.AbortWithStatus(code int): 调用该函数会终止当前中间件函数的执行,并返回指定的HTTP状态码给客户端

4. c.NextWithError(): 调用该函数会将控制权交给下一个中间件函数,同时传递一个错误给下一个中间件函数或路由处理函数

5. c.IsAborted(): 该函数用于判断当前请求是否已经被终止,返回一个布尔值表示请求是否已经被终止

看一个简单的使用流程控制的例子

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func test(c *gin.Context) {
	fmt.Println("test")
	c.JSON(200, gin.H{
		"message": "Test",
	})
}

func m1(c *gin.Context) {
	fmt.Println("m1 begin")
	c.Next()
	fmt.Println("m1 end")
}

func m2(c *gin.Context) {
	fmt.Println("m2 begin")
	c.Next()
	fmt.Println("m2 end")
}

func main() {
	router := gin.Default()
	router.GET("/test", m1, m2, test)

	router.Run()
}
// m1 begin
// m2 begin
// test
// m2 end
// m1 end

 c.Next()的作用是先调用下一个函数,下一个函数执行完之后再回头执行中间件后面的语句

整个过程就像洋葱一样

 

内置中间件

Gin框架也内置一些中间件,可以直接使用

func BasicAuth(accounts Accounts) HandlerFunc
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc
func Bind(val interface{}) HandlerFunc
func ErrorLogger() HandlerFunc
func ErrorLoggerT(typ ErrorType) HandlerFunc
func Logger() HandlerFunc
func LoggerWithConfig(conf LoggerConfig) HandlerFunc
func LoggerWithFormatter(f LogFormatter) HandlerFunc
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc
func Recovery() HandlerFunc
func RecoveryWithWriter(out io.Writer) HandlerFunc
func WrapF(f http.HandlerFunc) HandlerFunc
func WrapH(h http.Handler) HandlerFunc

而在使用gin.Default()返回的gin.Engine,会默认使用Recovery和Logger中间件,从gin.Default的源码可以看出来

// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine {
	debugPrintWARNINGDefault()
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

 如果不想使用默认中间件,可以使用gin.New()方法返回一个不带中间件的gin.Engine对象

总结

中间件是一个将具体业务和底层逻辑解耦的组件,在后端开发中有很多应用场景,像拦截、鉴权、日志等功能可以通过中间件简单的实现

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在gin框架接收POST请求并在请求到达处理程序之前进行中间件处理,可以使用gin中间件功能。以下是一个示例中间件,它可以将POST请求的请求体的JSON解析为一个结构体,并将其绑定到请求的上下文: ```go func JsonMiddleware() gin.HandlerFunc { return func(c *gin.Context) { if c.Request.Method == "POST" { var data interface{} err := c.BindJSON(&data) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.Set("json_data", data) } c.Next() } } ``` 在这个中间件,我们首先检查请求的HTTP方法是否为POST。如果是,我们尝试将请求体的JSON解析为一个结构体。如果解析失败,我们返回一个HTTP 400错误响应,并终止请求。否则,我们将解析后的数据绑定到请求上下文的“json_data”键,并继续处理请求。 要在gin应用程序使用这个中间件,我们只需要在路由注册之前将其添加到应用程序的中间件: ```go router := gin.Default() router.Use(JsonMiddleware()) router.POST("/my-endpoint", func(c *gin.Context) { data := c.MustGet("json_data") // 处理请求数据 }) ``` 在这个示例,我们使用gin.Default()创建一个新的路由器实例,并使用JsonMiddleware()函数添加一个中间件到路由器的中间件。然后,我们注册一个POST处理程序,该处理程序使用c.MustGet("json_data")从请求上下文获取JSON解析后的数据,并对数据进行处理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值