gin中间件

        在web应用服务中,完整的业务处理在技术上包含客户端操作,服务端处理,返回处理结果给客户端三个步骤。但是在在更负责的业务和需求场景。一个完整的系统可能要包含鉴权认证,权限管理,安全检查,日志记录等多维的系统支持。

        鉴权认证,权限管理,安全检查,日志记录等这些保障和支持系统业务属于全系统的业务,和具有的系统业务没有关联,对于系统中的所有业务都适用。

        我们可以将上述描述所涉及的通用业务单独抽离并进行开发,然后以插件化的形式进行对接,这样既保证了功能的完整,又有效的将具体业务和系统功能进行解耦,还可以达到灵活配置的作用。

        这种通用业务独立开发并灵活配置使用的组件,一般称为中间件。因为其位于服务器和实际业务处理程序之间。其含义在于在请求和具体业务逻辑之间增加某些操作。

一. 中间件定义

        在gin中,中间件称为middleware,中间件的类型定义如下:

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)

        HandlerFunc是一个函数类型,接收一个Context参数,函数由于编写中间件的处理逻辑。

type HandlerFunc func(*Context)其实就是代表一个中间件。

二. 中间件Use用法

        在gin中,中间件的全局注册使用的是gin.Engine的Use方法。

        通常我们使用gin.Default()方法来创建一个gin.Engine对象,该函数默认注册了Logger(), Recovery()两个中间件。

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

// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
// By default, gin.DefaultWriter = os.Stdout.
func Logger() HandlerFunc {
	return LoggerWithConfig(LoggerConfig{})
}

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
func Recovery() HandlerFunc {
	return RecoveryWithWriter(DefaultErrorWriter)
}

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

         gin.Engine的Use方法接收一个可变参数,可以按照自定义多个中间件传入,参数类型为HandlerFunc,即中间件类型。

// 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"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

// 定义中间件
func MiddleWare() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		fmt.Println("中间件开始执行")
		//设置变量到Context的key中,可以通过Get获取
		c.Set("request", "中间件")
		status := c.Writer.Status()
		fmt.Println("中间件执行完毕 ", status)
		t2 := time.Since(t)
		fmt.Println("time:", t2)
	}
}

func main() {
	r := gin.Default()
	//注册中间件
	r.Use(MiddleWare())

	r.GET("/ce1", func(c *gin.Context) {
		//取值
		req, _ := c.Get("request")
		fmt.Println("ce1 req: ", req)
		c.JSON(http.StatusOK, gin.H{"message1": "ce1 ok"})
	})

	r.GET("/ce2", func(c *gin.Context) {
		//取值
		req, _ := c.Get("request")
		fmt.Println("ce2 req: ", req)
		c.JSON(http.StatusOK, gin.H{"message2": "ce2 ok"})
	})

	r.Run()
}

输出结果:

 四. 局部中间件

  • 只有注册了中间件的路由才会执行中间件
package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

// 定义中间件
func MiddleWare() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		fmt.Println("中间件开始执行")
		//设置变量到Context的key中,可以通过Get获取
		c.Set("request", "中间件")
		status := c.Writer.Status()
		fmt.Println("中间件执行完毕 ", status)
		t2 := time.Since(t)
		fmt.Println("time:", t2)
	}
}

func main() {
	r := gin.Default()

	//给/ce1路由注册中间件
	r.GET("/ce1", MiddleWare(), func(c *gin.Context) {
		//取值
		req, _ := c.Get("request")
		fmt.Println("ce1 req: ", req)
		c.JSON(http.StatusOK, gin.H{"message1": "ce1 ok"})
	})

	r.GET("/ce2", func(c *gin.Context) {
		//取值
		req, _ := c.Get("request")
		fmt.Println("ce2 req: ", req)
		c.JSON(http.StatusOK, gin.H{"message2": "ce2 ok"})
	})

	r.Run()
}

五. 流程控制

        gin.Context中有一些方法可以控制中间件的执行流程。

  • c.Next(): 调用该函数会将控制权交给下一个中间件函数,如果没有下一个中间件函数,则将控制权交给处理请求的路由处理函数
  •  c.Abort(): 调用该函数会立即终止当前中间件函数的执行,并且不会再调用后续的中间件函数或路由处理函数
  • c.AbortWithStatus(code int): 调用该函数会终止当前中间件函数的执行,并返回指定的HTTP状态码给客户端
  • c.NextWithError(): 调用该函数会将控制权交给下一个中间件函数,同时传递一个错误给下一个中间件函数或路由处理函数
  • c.IsAborted(): 该函数用于判断当前请求是否已经被终止,返回一个布尔值表示请求是否已经被终止

一个使用Next方法的简单例子:

         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
  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Gin框架中,JWT(JSON Web Token)是一种常用的身份验证和授权机制。JWT是一种基于JSON的开放标准(RFC 7519),用于在网络应用间传递信息。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。 在Gin中使用JWT中间件可以实现对请求进行身份验证和授权。下面是使用Gin中间件JWT的步骤: 1. 导入相关的包: ```go import ( "github.com/gin-gonic/gin" "github.com/dgrijalva/jwt-go" ) ``` 2. 定义JWT中间件: ```go func AuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { tokenString := c.GetHeader("Authorization") if tokenString == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) c.Abort() return } token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { // 验证签名的密钥 return []byte("secret"), nil }) if err != nil || !token.Valid { c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) c.Abort() return } // 将解析后的token存储到上下文中,方便后续处理 c.Set("token", token) c.Next() } } ``` 3. 在需要进行身份验证和授权的路由上使用中间件: ```go router := gin.Default() router.GET("/protected", AuthMiddleware(), func(c *gin.Context) { // 从上下文中获取解析后的token token := c.MustGet("token").(*jwt.Token) // 在这里可以进行进一步的处理,如获取用户信息等 // ... c.JSON(http.StatusOK, gin.H{"message": "Authorized"}) }) router.Run(":8080") ``` 这样,当访问`/protected`路由时,会先经过JWT中间件进行身份验证和授权,只有在验证通过的情况下才会执行后续的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值