Gin中间件

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

定义中间件

Gin中的中间件必须是一个 gin.HandlerFunc 类型。

c.Next()

调用后续的处理函数

记录接口耗时的中间件

定义一个统计请求耗时的中间件 m1

package mainimport ("fmt""github.com/gin-gonic/gin""net/http""time"
)// HandlerFunc
func indexHandler(c *gin.Context) {fmt.Println("index")c.JSON(http.StatusOK, gin.H{"msg": "index",})
}// 定义一个中间件:统计请求处理函数的耗时
func m1(c *gin.Context) {fmt.Println("m1 in...")// 计时start := time.Now()c.Next()cost := time.Since(start)fmt.Printf("cost:%v\n", cost)fmt.Println("m1 out...")
}func main() {r := gin.Default()// GET(relativePath string, handlers ...HandlerFuncs) IRouter r.GET("/index", m1, indexHandler)r.Run(":9090")
}

在这里插入图片描述
在这里插入图片描述

全局注册1个中间件

func main() {r := gin.Default()r.Use(m1) // 全局注册中间件函数m1// GET(relativePath string, handlers ...HandlerFuncs() IRouterr.GET("/index", indexHandler)r.GET("/shop", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"msg": "shop",})})r.GET("/user", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"msg": "user",})})r.Run(":9090")
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

全局注册2个中间件

在这里插入图片描述
在这里插入图片描述

package mainimport ("fmt""github.com/gin-gonic/gin""net/http""time"
)// HandlerFunc
func indexHandler(c *gin.Context) {fmt.Println("index")c.JSON(http.StatusOK, gin.H{"msg": "index",})
}// 定义一个中间件:统计请求处理函数的耗时
func m1(c *gin.Context) {fmt.Println("m1 in...")// 计时start := time.Now()c.Next() // 调用后续的处理函数//c.Abort() // 阻止调用后续的处理函数cost := time.Since(start)fmt.Printf("cost:%v\n", cost)fmt.Println("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 ...HandlerFuncs() IRouterr.GET("/index", indexHandler)r.Run(":9090")
}

在这里插入图片描述
在这里插入图片描述

c.Abort()

在这里插入图片描述

阻止调用后续的处理函数

package mainimport ("fmt""github.com/gin-gonic/gin""net/http""time"
)// HandlerFunc
func indexHandler(c *gin.Context) {fmt.Println("index")c.JSON(http.StatusOK, gin.H{"msg": "index",})
}// 定义一个中间件:统计请求处理函数的耗时
func m1(c *gin.Context) {fmt.Println("m1 in...")// 计时start := time.Now()c.Next() // 调用后续的处理函数//c.Abort() // 阻止调用后续的处理函数cost := time.Since(start)fmt.Printf("cost:%v\n", cost)fmt.Println("m1 out...")
}func m2(c *gin.Context) {fmt.Println("m2 in...")c.Abort()fmt.Println("m2 out...")
}func main() {r := gin.Default()r.Use(m1, m2) // 全局注册中间件函数m1, m2// GET(relativePath string, handlers ...HandlerFuncs() IRouterr.GET("/index", indexHandler)r.Run(":9090")
}

在这里插入图片描述

在这里插入图片描述

return

在这里插入图片描述

func m2(c *gin.Context) {fmt.Println("m2 in...")c.Abort()returnfmt.Println("m2 out...")
}

高阶中间件

// 接受一个布尔参数 doCheck 来决定是否进行检查
// 如果 doCheck 为 true,可以在中间件中添加检查
// 如果为 false,则直接调用 c.Next(),继续请求处理
// 使得可以灵活控制是否需要验证
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(false))// GET(relativePath string, handlers ...HandlerFuncs() IRouterr.GET("/index", indexHandler)r.Run(":9090")
}

在这里插入图片描述
在这里插入图片描述

记录响应体的中间件

有时候可能会想要记录下某些情况下返回给客户端的响应数据,这个时候就可以编写一个中间件来搞定。

type bodyLogWriter struct {gin.ResponseWriter               // 嵌入gin框架ResponseWriterbody               *bytes.Buffer // 我们记录用的response
}// Write 写入响应体数据
func (w bodyLogWriter) Write(b []byte) (int, error) {w.body.Write(b)                  // 我们记录一份return w.ResponseWriter.Write(b) // 真正写入响应
}// ginBodyLogMiddleware 一个记录返回给客户端响应体的中间件
// https://stackoverflow.com/questions/38501325/how-to-log-response-body-in-gin
func ginBodyLogMiddleware(c *gin.Context) {blw := &bodyLogWriter{body: bytes.NewBuffer([]byte{}), ResponseWriter: c.Writer}c.Writer = blw // 使用我们自定义的类型替换默认的c.Next() // 执行业务逻辑fmt.Println("Response body: " + blw.body.String()) // 事后按需记录返回的响应
}

跨域中间件cors

推荐使用社区的https://github.com/gin-contrib/cors 库,一行代码解决前后端分离架构下的跨域问题。

注意: 该中间件需要注册在业务处理函数前面。

这个库支持各种常用的配置项,具体使用方法如下。

package mainimport ("time""github.com/gin-contrib/cors""github.com/gin-gonic/gin"
)func main() {router := gin.Default()// CORS for https://foo.com and https://github.com origins, allowing:// - PUT and PATCH methods// - Origin header// - Credentials share// - Preflight requests cached for 12 hoursrouter.Use(cors.New(cors.Config{AllowOrigins:     []string{"https://foo.com"},  // 允许跨域发来请求的网站AllowMethods:     []string{"GET", "POST", "PUT", "DELETE",  "OPTIONS"},  // 允许的请求方法AllowHeaders:     []string{"Origin", "Authorization", "Content-Type"},ExposeHeaders:    []string{"Content-Length"},AllowCredentials: true,AllowOriginFunc: func(origin string) bool {  // 自定义过滤源站的方法return origin == "https://github.com"},MaxAge: 12 * time.Hour,}))router.Run()
}

当然可以简单的像下面的示例代码那样使用默认配置,允许所有的跨域请求。

func main() {router := gin.Default()// same as// config := cors.DefaultConfig()// config.AllowAllOrigins = true// router.Use(cors.New(config))router.Use(cors.Default())router.Run()
}

注册中间件

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

为全局路由注册

func main() {// 新建一个没有任何默认中间件的路由r := gin.New()// 注册一个全局中间件r.Use(StatCost())r.GET("/test", func(c *gin.Context) {name := c.MustGet("name").(string) // 从上下文取值log.Println(name)c.JSON(http.StatusOK, gin.H{"message": "Hello world!",})})r.Run()
}

为某个路由单独注册

// 给/test2路由单独注册中间件(可注册多个)r.GET("/test2", StatCost(), func(c *gin.Context) {name := c.MustGet("name").(string) // 从上下文取值log.Println(name)c.JSON(http.StatusOK, gin.H{"message": "Hello world!",})})

为路由组注册中间件

为路由组注册中间件有以下两种写法。

写法1

shopGroup := r.Group("/shop", StatCost())
{shopGroup.GET("/index", func(c *gin.Context) {...})...
}

写法2

shopGroup := r.Group("/shop")
shopGroup.Use(StatCost())
{shopGroup.GET("/index", func(c *gin.Context) {...})...
}

中间件注意事项

gin默认中间件

gin.Default() 默认使用了 LoggerRecovery 中间件,其中:

  • Logger 中间件将日志写入 gin.DefaultWriter,即使配置了 GIN_MODE=release
  • Recovery 中间件会 recover 任何 panic。如果有panic的话,会写入500响应码。

如果不想使用上面两个默认的中间件,可以使用 gin.New() 新建一个没有任何默认中间件的路由。

gin中间件中使用 goroutine

当在中间件或 handler 中启动新的 goroutine 时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本( c.Copy() )。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/430467.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上半年亏损扩大/百亿资产重组终止,路畅科技如何“脱困”?

在智能网联汽车市场形势一片大好的前提下,路畅科技上半年的营收却出现了下滑,并且亏损也进一步扩大。 2024年半年度报告显示,路畅科技营业收入1.35亿元,同比下滑7.83%;实现归属上市公司股东的净利润为亏损2491.99万元…

一篇讲完CSS的核心内容

目录 一 、引言 1.1CSS概念 二、 CSS简介 2.1 什么是CSS 2.2 CSS能干什么 2.3 CSS书写规范 2.4 基础语法 三、 CSS导入方式 3.1 内嵌方式(内联方式) 3.2 内部方式 3.3 外部方式 四、 CSS选择器 4.1 基本选择器 [重点] 4.2 属性选择器 五、 CSS属性 5.1 文字属性…

sheng的学习笔记-AI-强化学习(Reinforcement Learning, RL)

AI目录:sheng的学习笔记-AI目录-CSDN博客 基础知识 什么是强化学习 强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体&#…

【RabbitMQ】RabbitMQ 的概念以及使用RabbitMQ编写生产者消费者代码

目录 1. RabbitMQ 核心概念 1.1生产者和消费者 1.2 Connection和Channel 1.3 Virtual host 1.4 Queue 1.5 Exchange 1.6 RabbitMO工作流程 2. AMQP 3.RabbitMO快速入门 3.1.引入依赖 3.2.编写生产者代码 ​3.3.编写消费者代码 4.源码 1. RabbitMQ 核心概念 在安装…

Blender软件三大渲染器Eevee、Cycles、Workbench对比解析

Blender 是一款强大的开源3D制作平台,提供了从建模、雕刻、动画到渲染、后期制作的一整套工具,广泛应用于电影、游戏、建筑、艺术等领域。 渲染101云渲染云渲6666 相比于其他平台,如 Autodesk Maya、3ds Max 或 Cinema 4D,Blende…

好用的idea方法分隔符插件

好用的idea方法分隔符插件

频率增强通道注意力机制(FECAM)学习总结

本文提出了一种新的频率增强通道注意力机制(FECAM),旨在解决时间序列预测中傅里叶变换因吉布斯现象导致的高频噪声问题。FECAM基于离散余弦变换,能自适应地模拟信道间的频率依赖性,有效避免预测误差。实验显示&#xf…

DANN GRL

域自适应是指在目标域与源域的数据分布不同但任务相同下的迁移学习,从而将模型在源域上的良好性能迁移到目标域上,极大地缓解目标域标签缺失严重导致模型性能受损的问题。 介绍一篇经典工作 DANN : 模型结构 在训练阶段需要预测如下两个任务…

委托的注册及注销+观察者模式

事件 委托变量如果公开出去,很不安全,外部可以随意调用 所以取消public,封闭它,我们可以自己书写两个方法,供外部注册与注销,委托调用在子方法里调用,这样封装委托变量可以使它更安全,这个就叫…

SpringBoot3核心特性-核心原理

目录 传送门前言一、事件和监听器1、生命周期监听2、事件触发时机 二、自动配置原理1、入门理解1.1、自动配置流程1.2、SPI机制1.3、功能开关 2、进阶理解2.1、 SpringBootApplication2.2、 完整启动加载流程 三、自定义starter1、业务代码2、基本抽取3、使用EnableXxx机制4、完…

JAVA自助高效安全无人台球茶室棋牌室系统小程序源码

​探索“自助高效安全无人台球茶室棋牌室系统”的奇妙之旅 🎱🍵🎲 🔍 初见惊艳:未来娱乐新体验 🔍 走进这家无人值守的台球茶室棋牌室,第一感觉就像是穿越到了未来!没有繁琐的前台登…

如何利用 opencv 进行 ROI(感兴趣)获取和实现 VR(虚拟现实) 演播室的播放

我是从事医疗软件的开发的。 经常需要从拍摄的医疗视频中获取出病理区域。并计算病理区域的周长和面积。 用 opencv 的术语,这就是感兴趣区域的获取。 (因为都是实时视频,所以速度很关键。代码效率很重要) 有时,需要标注出病理区域,并将非病理区域从视频中去除掉。 如果将…

中电金信 :基于开放架构的私有云建设实践

01开放架构私有云诞生背景 随着国产化创新建设的深化,产业侧行业软件持续进行云原生改造,金融机构拥抱云和容器技术,实现数智化转型已是大势所趋。近年,云原生技术以及架构发展速度更是惊人,私有云开始有了新架构、有了…

小柴冲刺软考中级嵌入式系统设计师系列一、计算机系统基础知识(6)可靠性与系统性能评测基础

目录 1、计算机可靠性 串联系统 并联系统 2、计算机系统的性能评价 性能评测的常用方法 基准测试程序 flechazohttps://www.zhihu.com/people/jiu_sheng 小柴冲刺嵌入式系统设计师系列总目录https://blog.csdn.net/qianshang52013/article/details/139975720?spm1001.2…

潮玩宇宙大逃杀宝石游戏搭建开发

潮玩宇宙大逃杀的开发主要涉及以下方面: 1. 游戏概念和设计: 核心概念定义:确定以潮玩为主题的宇宙背景、游戏的基本规则和目标。例如,玩家在宇宙场景中参与大逃杀竞技,目标是成为最后存活的玩家。 玩法模式设计&a…

基于Es和智普AI实现的语义检索

1、什么是语义检索 语义检索是一种利用自然语言处理(NLP)和人工智能(AI)技术来理解搜索查询的语义,以提供更准确和相关搜索结果的搜索技术,语义检索是一项突破性的技术,旨在通过深入理解单词和…

如何使用GLib的单向链表GSList

单向链表是一种基础的数据结构,也是一种简单而灵活的数据结构,本文讨论单向链表的基本概念及实现方法,并着重介绍使用GLib的GList实现单向链表的方法及步骤,本文给出了多个实际范例源代码,旨在帮助学习基于GLib编程的读…

uni-app快速入门

目录 一、什么是 uni-app二、快速创建 uni-app 项目1.创建 uni-app2.运行 uni-app 三、uni-app 相对传统 H5 的变化1.网络模型的变化2.文件类型变化3.文件内代码架构的变化4.外部文件引用方式变化5.组件/标签的变化6.js的变化(1)运行环境从浏览器变成v8引…

Leetcode—329. 矩阵中的最长递增路径【困难】

2024每日刷题&#xff08;165&#xff09; Leetcode—329. 矩阵中的最长递增路径 dfs dp实现代码 class Solution { public:int longestIncreasingPath(vector<vector<int>>& matrix) {// 9 9 4// 6 6 8// 2 1 1// 1 1 2// 2 2 1// 3 4 2int m …