Gin框架——中间件

8 篇文章 0 订阅
2 篇文章 0 订阅

1. 介绍

中间件在B/S模式中的架构的作用

中间件在B/S模式下起到了功能层的作用。当用户从WEB界面向服务器提交了数据请求或者应用请求时,功能层负责将这些请求分类为数据或应用请求,再向数据库发出数据交换申请。数据库对请求进行筛选处理之后,再将所需的数据通过功能层传递回到用户端。通过如此处理,单一用户可以进行点对面的操作,无需通过其他软件进行数据转换。

—节选自《中间件》百度百科

2. 中间件的分类

全局中间件路由组中间件单个路由中间件

3. 中间件设置方式

3.1 全局中间件

**介绍:**全局中间件设置之后对全局的路由都起作用

**注册方式:**通过默认路由来设置。

分类:

  • 一次设置一个中间件
  • 一次设置多个中间件。
router := gin.New()
//一次设置多个中间件 
router.Use(Logger(), Recovery())
//一次设置一个中间件
router.Use(gin.Logger())
router.Use(gin.Recovery())

3.2 路由组中间件

**介绍:**路由组中间件仅对该路由组下面的路由起作用

设置方式:

  1. 在声明路由组的同时设置路由组中间件

    • authorized := router.Group("/", CookieMiddleware())
      
  2. 先声明路由组然后再通过use进行设置

    • authorized := router.Group("/")
      authorized.Use(CookieMiddleware())
      

3.3 单个路由中间件

**介绍:**单个路由中间件仅对一个路由起作用

设置方式:

  • 单个路由设置单个中间件
router.GET("/login", LoginMiddleware, handler)
  • 单个路由设置多个中间件
router.GET("/mid", TimeMiddleware, CookieMiddleware(), handler)

4. 中间件的两个专属方法

4.1 ctx.Next() 继续

在程序进入中间件的时候需要先进行一些处理,然后去 执行核心业务,在执行完核心业务之后再回来执行该中间件。

跟Java Spring 里面的AOP很像

router.GET("/mid", TimeMiddleware, handler)
// 记录函数执行的时间中间件
func TimeMiddleware(ctx *gin.Context) {
	fmt.Println("------------TimeMiddleware 计时开始------------")
	start := time.Now()
	ctx.Next()
	Since := time.Since(start)
	fmt.Println(Since)
	fmt.Println("++++++++++++TimeMiddleware 计时结束++++++++++++")
}
func handler(ctx *gin.Context) {
	fmt.Println("#############正常的handler执行开始#############")
	ctx.JSON(http.StatusOK, gin.H{
		"ziop": "ziop",
	})
}

TimeMiddleware

4.2 ctx.Abort() 中断

在程序进入中间件之后我们进行了一些操作,判断该用户不满足访问这个请求的条件,这个时候我们就需要终止这个请求,不让其继续执行,这个时候就使用到了Abort

router.GET("/login", LoginMiddleware, handler)
func LoginMiddleware(ctx *gin.Context) {
	fmt.Println("------------LoginMiddleware 计时开始------------")
	login := ctx.Query("login")
	if login != "" {
		ctx.Next()
		fmt.Println("Hi, " + login + ",欢迎访问ziop的小屋")
	} else {
		ctx.Abort()
		fmt.Println("未登录,拒绝访问")
	}
	fmt.Println("++++++++++++LoginMiddleware 计时结束++++++++++++")
}
  • 测试一

    image-20220505111321982

    image-20220505111600490

  • 测试二

  • image-20220505111527998

    image-20220505111541432

5. 本质

Gin中的中间件实际上还是一个Gin中的 gin.HandlerFunc,也就是说他和其他的处理器都差不多,通过中间件的使用可以使多个处理器同时处理一个请求。

如果学过Javaweb或者说学过spring boot的同学可以将Gin里面的中间件理解为拦截器(filter)之类的工具。

6. 使用场景

6.1 场景一 权限验证

​ 有些网页在访问的时候需要用户登录之后才可以发送请求,这个时候我们就必须写一个处理器来检测用户是否登录如果登录的话就可以正常访问,如果用户没有登录就拒绝请求的处理。

​ 起初,我们当让可以使用一个处理器来写: 这个处理器先判断一下用户是否登录然后再执行相应的处理。一个接口可以这样写,两个接口可以这样写。但是当需求量逐渐增多的时候我们发现这样写的话就会很麻烦。

​ 这个时候我们发现可以抽出来一个公共的方法来进行验证用户是否登录。然后我们的核心业务代码就会大大减少了,同时也提升了开发的效率。这样我们对需要限制访问的方法加上这个公共的方法,不需要限制的方法不加上这个公共方法就简单的实现了我们的需求。

​ 然而这个公共的方法就是我们这里要提到的中间件。

6.2 场景二 检测时间

​ 有时候我们想要检测一下某个请求的处理时间,来做一些日志,以便于以后有错误需要排查的时候方便排查。这时候就可以写一个中间件来检测处理时间。

router.GET("/mid", TimeMiddleware, handler)
// 记录函数执行的时间中间件
func TimeMiddleware(ctx *gin.Context) {
	fmt.Println("------------TimeMiddleware 计时开始------------")
	start := time.Now()
	ctx.Next()
	Since := time.Since(start)
	fmt.Println(Since)
	fmt.Println("++++++++++++TimeMiddleware 计时结束++++++++++++")
}
func handler(ctx *gin.Context) {
	fmt.Println("#############正常的handler执行开始#############")
	ctx.JSON(http.StatusOK, gin.H{
		"ziop": "ziop",
	})
}

TimeMiddleware

6.3 场景三 数据处理

我们有可能在正式处理核心业务之前会先对请求的数据进行一些处理,这个时候也可以使用到中间件。就像下面的案例就是在处理之前先进行了一次Cookie的设置。

router.GET("/mid", CookieMiddleware(), handler)
func CookieMiddleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		fmt.Println("------------CookieMiddleware start------------")
		user := ctx.Query("user")
		fmt.Printf("ctx.Request.Host: %v\n", strings.Split(ctx.Request.Host, ":")[0])
		ctx.SetCookie("user", user, 0, "", strings.Split(ctx.Request.Host, ":")[0], false, true)
		fmt.Println("++++++++++++CookieMiddleware end++++++++++++")

	}
}

7. 整个案例代码

package main

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

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

func main() {
	// 新建一个没有任何默认中间件的路由
	router := gin.New()
	//----------------------------------------------------------------------
	//  全局中间件
	//  全局中间件
	// Logger 中间件将日志写入 gin.DefaultWriter,即使你将 GIN_MODE 设置为 release。
	//  gin.DefaultWriter = os.Stdout  默认的日志输出是Stdout 也就是控制台输出
	router.Use(gin.Logger())

	// Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500。
	// 这样的好处就是一旦有一个服务不能正常运行了,也只是会影响到一个请求。
	// 不会影响到整个服务器的运行,不至于导致整个项目的瘫痪
	router.Use(gin.Recovery())

	//----------------------------------------------------------------------
	//路有组中间件
	// 认证路由组
	// authorized := router.Group("/", AuthRequired())
	// 和使用以下两行代码的效果完全一样:
	authorized := router.Group("/admin")
	// 路由组中间件! 在此例中,我们在 "authorized" 路由组中使用自定义创建的
	// AuthRequired() 中间件
	authorized.Use(TimeMiddleware)
	{
		authorized.POST("/login", handler)
		authorized.POST("/submit", handler)
		authorized.POST("/read", handler)

		// 嵌套路由组
		testing := authorized.Group("testing")
		testing.GET("/analytics", handler)
	}
	//----------------------------------------------------------------------
	//单个路由中间件
	//单独为某个路由设置中间件
	router.GET("/mid", TimeMiddleware, CookieMiddleware(), handler)
	router.GET("/login", LoginMiddleware, handler)
	// 优雅的退出服务
	endless.ListenAndServe(":8000", router)
}

func handler(ctx *gin.Context) {
	fmt.Println("#############正常的handler执行开始#############")
	ctx.JSON(http.StatusOK, gin.H{
		"ziop": "ziop",
	})
}

func CookieMiddleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		fmt.Println("------------CookieMiddleware start------------")
		user := ctx.Query("user")
		fmt.Printf("ctx.Request.Host: %v\n", strings.Split(ctx.Request.Host, ":")[0])
		ctx.SetCookie("user", user, 0, "", strings.Split(ctx.Request.Host, ":")[0], false, true)
		fmt.Println("++++++++++++CookieMiddleware end++++++++++++")

	}
}

// 记录函数执行的时间中间件
func TimeMiddleware(ctx *gin.Context) {
	fmt.Println("------------TimeMiddleware 计时开始------------")
	start := time.Now()
	ctx.Next()
	Since := time.Since(start)
	fmt.Println(Since)
	fmt.Println("++++++++++++TimeMiddleware 计时结束++++++++++++")
}

// 登录检测中间件
func LoginMiddleware(ctx *gin.Context) {
	fmt.Println("------------LoginMiddleware 计时开始------------")
	login := ctx.Query("login")
	if login != "" {
		ctx.Next()
		fmt.Println("Hi, " + login + ",欢迎访问ziop的小屋")
	} else {
		ctx.Abort()
		fmt.Println("未登录,拒绝访问")
	}
	fmt.Println("++++++++++++LoginMiddleware 计时结束++++++++++++")
}

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ziop-三月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值