Go Gin web框架的路由原理及中间件原理

本文涉及的产品
云原生网关 MSE Higress,422元/月
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: Go Gin web框架的路由原理及中间件原理

一、Gin框架的路由原理:

参考:

首先了解下什么是路由?

简而言之,http路由即是一条http请求的“向导”,根据URI上的路径,指引该条请求到对应的方法里去执行然后返回,中间可能会执行一些中间件。其次,路由又分为 静态路由,动态路由...

  • 静态路由: 框架/用户提前生成一个路由表,一般是map结构,key为URL上的path,value为代码执行点(处理函数),

    • 优点:只需要读取map,没有任何开销,速度奇快
    • 缺点:无法正则匹配路由,只能逐一对应,模糊匹配的场景无法使用
  • 动态路由: 用户定义好路由匹配规则,框架匹配路由时,根据规则动态的去规划路由

    • 优点:适应性强,解决了静态路由的缺点
    • 缺点:相比静态路由有开销,具体视算法和路由匹配规则而定

gin框架作为一个轻量级的web框架,采用的是字典树(前缀树)的方式实现的动态路由。当 gin 注册路由时,会根据不同的 Method 分别注册不同的路由树,比如 这四个请求,会分别注册四棵路由树出来:

GET    /user/{userID} HTTP/1.1
POST   /user/{userID} HTTP/1.1
PUT    /user/{userID} HTTP/1.1
DELETE /user/{userID} HTTP/1.1

在这里插入图片描述

gin路由注册的示例代码及其前缀树示意图,分别如下:

r := gin.New()
r.GET("/user/:name", routeUser)

func routeUser(c *gin.Context){
    //todo something
}

在这里插入图片描述

关于更多字典树的细节可以看这里

  • 字典树(Trie树):是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计

    • 优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
    • 复杂度分析:字典树其实是一种用空间换时间的算法,它占用的空间一般很大,但非常高效,插入和查询的时间复杂度都是 O(1) 的。

然而普通的字典树每个节点只能存储一个字符,这意味着面对较长的字符串仍然要向下探寻多个节点,这存在着浪费,因此就有了压缩字典树。

  • 压缩字典树:是trie树的一种,也称单词查找树(前缀树),善于进行字符串检索、取字符串最长公共前缀、以及排序,常应用在搜索引擎中,例如:百度输入某个字可能自动弹出匹配到的词组出来

在这里插入图片描述

  • ③ 字典树与压缩字典树的区别

    • 压缩字典树 每个节点不仅仅只存一个字符,而是取字符串的最长公共前缀。
    • 压缩字典树和标准字典树最大的不同点就节点的数量与插入字符串的个数成正比,而不是与字符串的长度成正比,所以当字符串数量越来越多,越密集且相似度极高的情况下,会退化成标准trie树。

下面分别是 /,/bear,/bell,/bid,/bull,/buy,/sell,/stock,/stop标准tire压缩 tire 的示意图:
在这里插入图片描述
在这里插入图片描述

  • ④ 关于字典树的查询操作 过程如下图:

    1. 先找共同前缀,比如下图中的s

      1. 再找目录 indices,比如下图中的eu
      2. 循环上面两步,直至当前path满足条件

在这里插入图片描述

二、Gin框架的中间件原理(Middleware)

参考:

中间件是为了过滤路由而发明的一种机制,也就是http请求来到时先经过中间件,再到具体的处理函数。

首先,Gin框架的中间件是基于洋葱模型的,如下图:
在这里插入图片描述
beforeFunc1和afterFunc1即是中间件1;afterFunc2和afterFunc2即是中间件2。

过程:请求到来时从最外层开始执行中间件1,然后进入第二层,依次执行完所有中间件最后到达主体函数,接着再一层一层的往外走再次执行中间件2...中间件1...最后返回,也有点像栈的概念。

其次,再来看下gin.Context的结构体的主要字段:

// gin.Context 结构体
type Context struct {
    ...
    handlers HandlersChain         // 函数指针切片对象
    index      int8                // 对应函数指针切片中的索引下标,执行c.Next()时会向后移动index下标位置
    ...
}

type HandlerFunc func(*Context)  // 函数指针
type HandlersChain []HandlerFunc // 函数指针切片

可以看到,gin框架的中间件函数和处理函数是以切片形式的调用链条存在的(本质上就是函数指针切片
在我们初始化了gin对象之后:r := gin.New()

  • 注册 [中间件函数/路由处理函数] 的过程:

r.Use(),也就是不断的在上述的 HandlersChain 函数指针切片后执行append操作,去依次向调用链条追加新注册的中间件函数

func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    group.Handlers = append(group.Handlers, middleware...)
    return group.returnObj()
}
  • 调用 [中间件函数/路由处理函数] 的过程:

如下图,gin框架正是通过移动切片下标 index 的位置,实现中间件的不断向后调用...
但是这个index要如何去移动呢?这就是gin框架中 c.Next()的作用了,这个函数会在每次调用时将index向后移动,从而依次调用已注册的中间件。

Gin框架的中间件调用过程原理图

func (c *Context) Next() {
    c.index++
    for c.index < int8(len(c.handlers)) {
        c.handlers[c.index](c)
        c.index++
    }
}
  • 停止调用后续 [中间件函数/路由处理函数] 的过程:

c.Abort()方法会阻止调用后续的中间件处理函数,正是因为它使得index移动到切片末尾了,所以后面的 [中间件/路由处理函数] 都没法继续执行了。

func (c *Context) Abort() {
    c.index = abortIndex
}

因此,gin框架的 [中间件函数/路由处理函数] 实际上都是以切片的形式的调用链条存在的(本质上就是函数指针切片),我们可以顺序调用也可以借助 c.Next() 方法实现嵌套调用。

三、总结

  1. gin框架路由使用字典树(前缀树),路由注册的过程是构造前缀树的过程,路由匹配的过程就是查找前缀树的过程。
  2. gin框架的 [中间件函数和处理函数] 是以切片的形式的调用链条存在的(本质上就是函数指针切片),我们可以顺序调用也可以借助 c.Next() 方法实现嵌套调用。
  3. 借助c.Set()和c.Get()方法我们能够在不同的中间件函数中传递数据。
目录
相关文章
|
3月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
3月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:使用 Gin 快速构建 Web 服务
Gin 是一个高效、轻量级的 Go 语言 Web 框架,支持中间件机制,非常适合开发 RESTful API。本文从安装到进阶技巧全面解析 Gin 的使用:快速入门示例(Hello Gin)、定义 RESTful 用户服务(增删改查接口实现),以及推荐实践如参数校验、中间件和路由分组等。通过对比标准库 `net/http`,Gin 提供更简洁灵活的开发体验。此外,还推荐了 GORM、Viper、Zap 等配合使用的工具库,助力高效开发。
|
4月前
|
存储 应用服务中间件 nginx
在使用Nginx之后,如何在web应用中获取用户IP以及相关原理
但总的来说,通过理解网络通信的基础知识,了解http协议以及nginx的工作方式,我们已经能在大多数情况下准确地获取用户的真实IP地址了,在调试问题或者记录日志时会起到很大的帮助。
250 37
|
7月前
|
中间件 关系型数据库 数据库
docker快速部署OS web中间件 数据库 编程应用
通过Docker,可以轻松地部署操作系统、Web中间件、数据库和编程应用。本文详细介绍了使用Docker部署这些组件的基本步骤和命令,展示了如何通过Docker Compose编排多容器应用。希望本文能帮助开发者更高效地使用Docker进行应用部署和管理。
194 19
|
7月前
|
开发框架 前端开发 Go
eino — 基于go语言的大模型应用开发框架(二)
本文介绍了如何使用Eino框架实现一个基本的LLM(大语言模型)应用。Eino中的`ChatModel`接口提供了与不同大模型服务(如OpenAI、Ollama等)交互的统一方式,支持生成完整响应、流式响应和绑定工具等功能。`Generate`方法用于生成完整的模型响应,`Stream`方法以流式方式返回结果,`BindTools`方法为模型绑定工具。此外,还介绍了通过`Option`模式配置模型参数及模板功能,支持基于前端和用户自定义的角色及Prompt。目前主要聚焦于`ChatModel`的`Generate`方法,后续将继续深入学习。
953 7
|
7月前
|
存储 开发框架 Devops
eino — 基于go语言的大模型应用开发框架(一)
Eino 是一个受开源社区优秀LLM应用开发框架(如LangChain和LlamaIndex)启发的Go语言框架,强调简洁性、可扩展性和可靠性。它提供了易于复用的组件、强大的编排框架、简洁明了的API、最佳实践集合及实用的DevOps工具,支持快速构建和部署LLM应用。Eino不仅兼容多种模型库(如OpenAI、Ollama、Ark),还提供详细的官方文档和活跃的社区支持,便于开发者上手使用。
1631 8
|
9月前
|
开发框架 Go 计算机视觉
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C++ 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。此外,在许多情况下,在各种平台上安装 OpenCV 是很麻烦的。使用纯Go开发的插件不仅在开发时方便,在项目部署和项目维护也能省很多时间精力。
234 5
|
10月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
849 4
|
10月前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
997 1
|
10月前
|
缓存 前端开发 中间件
go语言中Web框架
【10月更文挑战第22天】
159 4