Go Gin web框架的路由原理及中间件原理
一、Gin框架的路由原理:
参考:
- go路由httprouter中的压缩字典树算法图解及c++实现
- Golang-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 的示意图:
- ④ 关于字典树的查询操作 过程如下图:
- 先找共同前缀,比如下图中的
s
- 再找目录 indices,比如下图中的
eu
- 循环上面两步,直至当前path满足条件
二、Gin框架的中间件原理(Middleware)
参考:
- go面试题 - gin中间件原理分析
- bilibili视频 - gin的中间件原理和简单手撸
中间件是为了过滤路由而发明的一种机制,也就是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向后移动,从而依次调用已注册的中间件。
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() 方法实现嵌套调用。
三、总结
- gin框架路由使用字典树(前缀树),路由注册的过程是构造前缀树的过程,路由匹配的过程就是查找前缀树的过程。另外,gin框架不支持路由的正则匹配。
- gin框架的 [中间件函数和处理函数] 是以切片的形式的调用链条存在的(本质上就是函数指针切片),我们可以顺序调用也可以借助 c.Next() 方法实现嵌套调用。
- 借助c.Set()和c.Get()方法我们能够在不同的中间件函数中传递数据。
Go Gin web框架的路由原理及中间件原理相关推荐
- Django基础-Web框架-URL路由
Django基础-Web框架-URL路由 一.Django基础–Web框架 MVC和MTV框架 MVC 把Web应用分为模型(M).视图(V).控制器(C)三层,他们之间以一种插件式的,松耦合的方式联 ...
- Go gin web框架介绍
gin框架介绍 一.gin框架介绍 gin是用go语言开发的一个web框架,简单易用,是一个轻量级框架. 二.为什么选择gin 1.运行响应非常快 2.快速开发 3.文档齐全 4.社区活跃 三.特性 ...
- gin框架学习-路由分组和中间件
路由分组和中间件 前言 一.路由分组 二.中间件 1.中间件简介 2.定义中间件 3.注册中间件 1)注册全局中间件 2)单独注册某个路由中间件 3)注册路由组中间件 4.中间件的嵌套 1)Next( ...
- Go语言WEB框架:路由注册
路由注册 路由注册用于建立URL路径与处理器函数(也可以叫控制器函数)的对应关系.一条路由规则由三部分组成: http请求方法 url路径 处理器函数 以下代码注册了一个处理器函数:Hello,当用户 ...
- ginapi服务器性能,基于gin web框架搭建RESTful API服务
这篇主要学习go项目中的项目结构.项目规范等知识,ROM采用的database/sql的写法. 1.技术框架 利用的是ginweb框架,然后ROM层选用database/sql,安装mysql驱动.安 ...
- Python:闭包(简介、使用方法、nonlocal修改闭包内使用的外部变量)、装饰器(定义、作用、通用装饰器、多个装饰器、带参数的装饰器、类装饰器、装饰器方式添加WEB框架的路由)
一.闭包的介绍 闭包可以保存函数内的变量 当闭包执行完毕,外部函数的变量才释放. # 闭包的作用:可以保存外部函数的变量 # 闭包的形成条件 # 1.函数嵌套 # 2.内部函数使用了外部函数的变量或者 ...
- 仿Gin搭建自己的web框架(七)
本篇介绍HTTP Basic Auth的实现以及Recovery机制. HTTP Basic Auth Basic Auth是一种开放平台认证方式,简单的说就是需要你输入用户名和密码才能继续访问.对于 ...
- python 后端web框架知识整理
1.Django 创建项目的命令? django-admin startproject 项目名称 python manage.py startapp 应用 app 名 2.Django 创建项目后,项 ...
- Go框架 gin 源码学习--路由的实现原理剖析
往期回顾: gin源码解析 - gin 与 net/http 的关系 gin 源码解析 - 详解http请求在gin中的流转过程 上面两篇文章基本讲清楚了 Web Server 如何接收客户端请求,以 ...
最新文章
- 算法设计思想(4)— 分治法
- 未来3大趋势:人工智能 产业互联网 大数据与算法
- 起源,机制与趋势,如何理解和定义城市大脑
- 用CSS实现的模式窗口效果,弹出固定大小的窗口
- Android之修改app名字客户需要升级需要注意的问题
- 使用Spring WebFlux从Corda节点流式传输数据
- python concurrent queue_Python的并发并行[2] - 队列[0] - queue 模块
- java map取值_Java Set接口 Map 与枚举
- 简单配置laravel
- IT 人士工作中的十不要!
- 微服务面试题 - Spring Cloud
- 推荐:详解AI加速器(最终篇)
- 悬崖帝国中文版下载|悬崖帝国中文破解版下载 v1.0绿色免安装版
- CentOS8下安装wget、wget2
- Unity Profiler分析器-Rendering
- python读取txt文档乱码解决
- kettle案例21-将字段值设置为常量
- 高性能Web应用程序–数据URI
- references column 'xxx' which is not in SELECT list
- Scala之set方法(超详细)