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

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
性能测试 PTS,5000VUM额度
简介: 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()方法我们能够在不同的中间件函数中传递数据。
目录
相关文章
|
28天前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
70 1
|
2月前
|
前端开发 Java API
JAVA Web 服务及底层框架原理
【10月更文挑战第1天】Java Web 服务是基于 Java 编程语言用于开发分布式网络应用程序的一种技术。它通常运行在 Web 服务器上,并通过 HTTP 协议与客户端进行通信。
35 1
|
3月前
|
安全 关系型数据库 Shell
Web安全-浅析CSV注入漏洞的原理及利用
Web安全-浅析CSV注入漏洞的原理及利用
172 3
|
2月前
|
存储 安全 前端开发
在前端开发中需要考虑的常见web安全问题和攻击原理以及防范措施
在前端开发中需要考虑的常见web安全问题和攻击原理以及防范措施
219 0
|
3月前
|
中间件 API 开发者
深入理解Python Web框架:中间件的工作原理与应用策略
在Python Web开发中,中间件位于请求处理的关键位置,提供强大的扩展能力。本文通过问答形式,探讨中间件的工作原理、应用场景及实践策略,并以Flask和Django为例展示具体实现。中间件可以在请求到达视图前或响应返回后执行代码,实现日志记录、权限验证等功能。Flask通过装饰器模拟中间件行为,而Django则提供官方中间件系统,允许在不同阶段扩展功能。合理制定中间件策略能显著提升应用的灵活性和可扩展性。
51 4
|
3月前
|
缓存 中间件 网络架构
Python Web开发实战:高效利用路由与中间件提升应用性能
在Python Web开发中,路由和中间件是构建高效、可扩展应用的核心组件。路由通过装饰器如`@app.route()`将HTTP请求映射到处理函数;中间件则在请求处理流程中插入自定义逻辑,如日志记录和验证。合理设计路由和中间件能显著提升应用性能和可维护性。本文以Flask为例,详细介绍如何优化路由、避免冲突、使用蓝图管理大型应用,并通过中间件实现缓存、请求验证及异常处理等功能,帮助你构建快速且健壮的Web应用。
35 1
|
4月前
|
Web App开发 测试技术 API
Web自动化测试框架(基础篇)--Selenium WebDriver工作原理和环境搭建
本文详细介绍了Selenium WebDriver的工作原理,包括其架构、通信机制及支持的浏览器,并指导读者如何在Python环境下搭建Selenium WebDriver的测试环境,从安装Python和Selenium库到编写并运行第一个自动化测试脚本。
258 0
|
4月前
|
存储 NoSQL 关系型数据库
Web中的数据库:原理、应用与代码实现
Web中的数据库:原理、应用与代码实现
137 0
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
159 3
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
173 45
下一篇
DataWorks