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

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: Go Gin web框架的路由原理及中间件原理

一、Gin框架的路由原理:

参考:

  • [go路由httprouter中的压缩字典树算法图解及c++实现

](https://blog.csdn.net/qq_17308321/article/details/89736691)

首先了解下什么是路由?

简而言之,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()方法我们能够在不同的中间件函数中传递数据。
目录
相关文章
|
5天前
|
开发框架 搜索推荐 中间件
中间件应用路由和URL重写
中间件应用路由和URL重写
12 3
|
12天前
|
缓存 监控 测试技术
【Go语言专栏】使用Go语言构建高性能Web服务
【4月更文挑战第30天】本文探讨了使用Go语言构建高性能Web服务的策略,包括Go语言在并发处理和内存管理上的优势、基本原则(如保持简单、缓存和并发控制)、标准库与第三方框架的选择、编写高效的HTTP处理器、数据库优化以及性能测试和监控。通过遵循最佳实践,开发者可以充分利用Go语言的特性,构建出高性能的Web服务。
|
12天前
|
中间件 Go
【Go语言专栏】Go语言中的中间件与路由处理
【4月更文挑战第30天】本文探讨了Go语言中的路由和中间件处理。路由负责根据URL映射到处理器,`net/http`包提供基础支持,而Gin和Echo等第三方库则提供更强大功能。中间件在请求处理链中执行预处理任务,如日志记录和认证。`net/http`包通过嵌套处理器实现中间件,而Gin和Echo则有更简洁的中间件接口。通过路由和中间件,可构建高效、结构良好的Web应用。建议进一步阅读官方文档以深化理解。
|
12天前
|
中间件 Go API
【Go 语言专栏】Go 语言中的 Web 框架比较与选择
【4月更文挑战第30天】本文对比了Go语言中的四个常见Web框架:功能全面的Beego、轻量级高性能的Gin、简洁高效的Echo,以及各自的性能、功能特性、社区支持。选择框架时需考虑项目需求、性能要求、团队经验和社区生态。开发者应根据具体情况进行权衡,以找到最适合的框架。
|
13天前
|
缓存 中间件 PHP
【PHP开发专栏】PHP框架中的路由与中间件
【4月更文挑战第29天】本文探讨了PHP框架中的路由和中间件概念。路由负责将HTTP请求映射到控制器方法,提供灵活的请求处理和URL管理。中间件则是在请求处理前后插入的代码,用于实现如身份验证、日志等功能,与业务逻辑解耦。通过Laravel框架的示例展示了如何定义路由和创建中间件,以实现代码的模块化和可维护性。
|
14天前
|
中间件 Go API
Golang深入浅出之-Go语言标准库net/http:构建Web服务器
【4月更文挑战第25天】Go语言的`net/http`包是构建高性能Web服务器的核心,提供创建服务器和发起请求的功能。本文讨论了使用中的常见问题和解决方案,包括:使用第三方路由库改进路由设计、引入中间件处理通用逻辑、设置合适的超时和连接管理以防止资源泄露。通过基础服务器和中间件的代码示例,展示了如何有效运用`net/http`包。掌握这些最佳实践,有助于开发出高效、易维护的Web服务。
28 1
|
17天前
|
SQL 安全 前端开发
Go语言Gin框架安全加固:全面解析SQL注入、XSS与CSRF的解决方案
Go语言Gin框架安全加固:全面解析SQL注入、XSS与CSRF的解决方案
|
18天前
|
Cloud Native 网络协议 Go
[云原生] Go web工作流程
[云原生] Go web工作流程
|
5月前
|
算法 NoSQL Java
2023年阿里高频Java面试题:分布式+中间件+高并发+算法+数据库
又到了一年一度的金九银十,互联网行业竞争是一年比一年严峻,作为工程师的我们唯有不停地学习,不断的提升自己才能保证自己的核心竞争力从而拿到更好的薪水,进入心仪的企业(阿里、字节、美团、腾讯.....)
|
9月前
|
NoSQL Java Redis
阿里Java高级岗中间件二面:GC+IO+JVM+多线程+Redis+数据库+源码
虽然“钱多、事少、离家近”的工作可能离技术人比较远,但是找到一份合适的工作,其实并不像想象中那么难。但是,有些技术人确实是认真努力工作,但在面试时表现出的能力水平却不足以通过面试,或拿到高薪,其实不外乎以下 2 个原因: