Gin框架源码解析
概要
目录
Gin路由详解
Gin框架路由之Radix Tree
一、路由树节点
二、请求方法树
三、路由注册以及匹配
中间件含义
Gin框架中的中间件
主要讲述Gin框架路由和中间件的详细解释。本文章将从Radix树(基数树或者压缩前缀树)、请求处理、路由方法树、路由的注册与匹配以及中间件的详细解释这五大部分入手。
Gin 框架 路由使用前缀树,路由注册的过程就是构造前缀树的过程,路由匹配的过程是查找前缀树 的过程。
Gin路由详解
Gin框架使用的是定制版本的httprouter。我们简单介绍下关于httprouer框架。
Httprouter是一个高性能路由分发器,它负责将不同方法的多个路径分别注册到各个handle函数。当收到请求时,Httprouter会快速查找请求的路径是否有相对应的处理函数,并执行相应的业务逻辑处理。
Httprouter使用基数树(radix tree)来进行高效的路径查找,这种数据结构适用于需要快速查找和匹配的场景。此外,Httprouter还支持两种通配符匹配,使得路由规则更加灵活和强大。
它为Gin提供了高效、灵活的路由匹配功能,使得Gin成为了一个高性能的Web框架。同时,Httprouter也是Go语言中广泛使用的一个路由库,独立于Gin框架,可以被其他Go语言的Web框架所使用。
Gin框架路由之Radix Tree
Radix Tree 是一种更节省空间的前缀树。对于基数树的每个节点,如果该节点是唯一的子树的话,就和父节点合并。
Radix Tree 可以被认为是一个简洁版的前缀树。我们注册路由的过程就是在构造前缀树的过程,具有公共前缀的节点也共享一个公共父节点。
如下图所示:GET方法对应的路由树。

- Priority(优先级):每个树级别上的子节点都按照优先级排序,其中优先级就是在子节点上注册的句柄数量。优点:优先匹配被大多数路由路径包含的节点(更快速定位)、最长路径可以优先匹配(成本补偿)。
- Handle: Get每个路由对应的实现函数。*<数字> 表示Handle处理函数的内存地址。
URL具有层级结构,并且都是有限的字符组,所以有很多常见的前缀。这样是的我们很容易将路由简化为更小的问题。
路由器为每种请求方法管理一颗单独的树。
一、路由树节点
type node struct {// 节点路径,比如上面的s,earch,和upportpath string// 和children字段对应, 保存的是分裂的分支的第一个字符// 例如search和support, 那么s节点的indices对应的"eu"// 代表有两个分支, 分支的首字母分别是e和uindices string// 儿子节点children []*node// 处理函数链条(切片)handlers HandlersChain// 优先级,子节点、子子节点等注册的handler数量priority uint32// 节点类型,包括static, root, param, catchAll// static: 静态节点(默认),比如上面的s,earch等节点// root: 树的根节点// catchAll: 有*匹配的节点// param: 参数节点nType nodeType// 路径上最大参数个数maxParams uint8// 节点是否是参数节点,比如上面的:postwildChild bool// 完整路径fullPath string
}
二、请求方法树
每一个HTTP method都对应一颗radix树,我们注册路由的时候都会调用addRoute函数。函数含义我们可以看到在注册路由的时候都是先根据请求方法获取对应的树,也就是gin框架会为每一个请求方法创建一颗对应的树。只不过需要注意一个细节是gin框架中请求方法对应树关系并不是使用map而是使用的切片,engine.trees的类型是methodThrees。
type methodTree struct {method stringroot *node
}type methodTrees []methodTree // slicefunc (engine *Engine) addRoute(method, path string, handlers HandlersChain) {// liwenzhou.com...// 获取请求方法对应的树root := engine.trees.get(method)if root == nil {// 如果没有就创建一个root = new(node)root.fullPath = "/"engine.trees = append(engine.trees, methodTree{method: method, root: root})}root.addRoute(path, handlers)
}
考点 :为什么用切片存储请求方法树,而不用map?
节省内存。HTTP请求方法数量也就9种,用切片存储和查询效率足够。只需要做出一次性内存申请即可。
三、路由注册以及匹配
路由注册函数:
- addRoute函数:将具有给定句柄的节点添加到路径中。不是并发安全的函数。
- insertChild函数:根据path本身进行分割,将/分开的部分分别作为节点保存,形成一颗树结构。参数匹配中的 : 和 * 的区别是,前者是匹配一个字段,后者是匹配后面所有的路径。
路由匹配:
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {// 这里使用了对象池c := engine.pool.Get().(*Context)// 这里有一个细节就是Get对象后做初始化c.writermem.reset(w)c.Request = reqc.reset()engine.handleHTTPRequest(c) // 我们要找的处理HTTP请求的函数engine.pool.Put(c) // 处理完请求后将对象放回池子
}func (engine *Engine) handleHTTPRequest(c *Context) {// 根据请求方法找到对应的路由树t := engine.treesfor i, tl := 0, len(t); i < tl; i++ {if t[i].method != httpMethod {continue}root := t[i].root// 在路由树中根据path查找value := root.getValue(rPath, c.Params, unescape)if value.handlers != nil {c.handlers = value.handlersc.Params = value.paramsc.fullPath = value.fullPathc.Next() // 执行函数链条c.writermem.WriteHeaderNow()return}c.handlers = engine.allNoRouteserveError(c, http.StatusNotFound, default404Body)
}
路由匹配是由节点的GetValue方法实现的。getValue根据给定的路径返回nodeValue值,里面保存的处理函数和匹配到的路径参数数据。如果找不到任何处理函数,会尝试TSR(尾随斜杠重定向)。
中间件含义
中间件是指处理HTTP请求的函数或组件,通常用于在请求到达目标处理程序之前或之后执行一些处理逻辑。中间件在Go语言中经常被使用,因为它提供了一种可扩展和可重用的机制,用于处理身份验证、授权、日志记录、错误处理等常见的Web应用程序需求。
中间件在Go语言主要是因为它提供了一种灵活、可扩展和可重用的机制,用于处理Web应用程序中的各种需求和逻辑。
中间件优势:
- 函数式编程思想:Go语言支持函数式编程风格,而中间件提供了一种将函数作为参数传递并在请求处理过程中进行组合和调用的机制。使得代码更加模块化和可重用性。
- 请求处理流程的可扩展性:中间件允许开发人员将请求处理流程分解为多个独立的函数或组件,这些 组件可以按照特定的顺序组合和调用。这种可扩展性使得开发人员可以轻松的添加、移除或替换中间件,以满足特定的应用程序需求。
- 前后置处理逻辑:中间件可以在请求到达目标处理程序之前或之前执行一些处理逻辑,例如身份验证、日志记录、错误处理等。这种机制使得开发人员可以轻松的请求处理过程中添加前后置处理逻辑,而无需修改现有的代码。
- 社区支持和普及。
Gin框架中的中间件
gin框架中涉及中间件相关有4个常用的方法,c.Next() 、c.Abort() 、c.Set()、c.Get()
Gin中间件函数和处理函数是以切片的形式调用链条存在的,我们可以顺序调用也可以借助c.Next函数方法实现嵌套调用。
c.Set()和c.Get()这两个方法多用于在多个函数之间通过c传递数据的,比如我们可以在认证中间件中获取当前请求的相关信息(userID等)通过c.Set()存入c,然后在后续处理业务逻辑的函数中通过c.Get()来获取当前请求的用户。c就像是一根绳子,将该次请求相关的所有的函数都串起来了。
c.Abort()中断整个调用链条,从当前函数返回。
相关文章:
Gin框架源码解析
概要 目录 Gin路由详解 Gin框架路由之Radix Tree 一、路由树节点 二、请求方法树 三、路由注册以及匹配 中间件含义 Gin框架中的中间件 主要讲述Gin框架路由和中间件的详细解释。本文章将从Radix树(基数树或者压缩前缀树)、请求处理、路由方法树…...
MacOS设置JAVA_HOME环境变量
首先先查看一下,系统当前使用的java是谁,可以使用/usr/libexec/java_home命令 % /usr/libexec/java_home /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home检查一下这个路径下的文件,发现这是一个jre的目录。加上-V参数看…...
闭眼检测实现
引言 这段代码是一个实时眼睛状态监测程序,可以用于监测摄像头捕获的人脸图像中的眼睛状态,判断眼睛是否闭合。具体应用实现作用说明如下: 1. 实时监测眼睛状态 通过摄像头捕获的实时视频流,检测人脸关键点并计算眼睛的 EAR&a…...
系列六、Java垃圾回收器主要有哪些?
一、Java垃圾回收器主要有哪些? UseSerialGC、UseParallelGC、UseConcMarkSweepGC、UseParallelNewGC、UseParallelOldGC、UseG1GC...
【7】Spring Boot 3 集成组件:缓存组件 spring cache + spring data redis
目录 【7】Spring Boot 3 集成组件:缓存组件 spring cache spring data redis什么是缓存抽象声明式注解JSR-107对应SpEL上下文数据 引入依赖cache 支持的缓存类型缓存类型配置NONESIMPLEREDIS自定义配置 CAFFEINE Hazelcast...总结 个人主页: 【⭐️个人主页】 需要…...
说说Java中的不可重入锁
什么是锁? 简单来讲在Java中,锁是一种用于并发控制的机制,用于保护共享资源,防止多个线程同时访问或修改数据导致的数据不一致性和线程安全问题。在Java虚拟机(JVM)中,每个对象都有一个相关联的…...
C++学习 --vector
目录 1, 什么是vector 2, 创建vector 2-1, 标准数据类型 2-2, 自定义数据类型 2-3, 其他创建方式 3, 操作vector 3-1, 赋值 3-2, 添加元素 3-2-1, 添加元素(assi…...
Android图片涂鸦,Kotlin(1)
Android图片涂鸦,Kotlin(1) import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Path import android.graphics.PointF import android.…...
upload-labs(1-17关攻略详解)
upload-labs pass-1 上传一个php文件,发现不行 但是这回显是个前端显示,直接禁用js然后上传 f12禁用 再次上传,成功 右键打开该图像 即为位置,使用蚁剑连接 连接成功 pass-2 源码 $is_upload false; $msg null; if (isse…...
《 机器人基础 》期末试卷(A)
一、填空题(30分,每空2分) 1. 按照相机的工作方式,机器人常用相机分为1)__ 单目摄像头 2)__ 双目摄像头 _ 3)_深度摄像头_ 三类。 2. 度量地图强调…...
Azure Machine Learning - Azure AI 搜索中的矢量搜索
矢量搜索是一种信息检索方法,它使用内容的数字表示形式来执行搜索方案。 由于内容是数字而不是纯文本,因此搜索引擎会匹配与查询最相似的矢量,而不需要匹配确切的字词。本文简要介绍了 Azure AI 搜索中的矢量支持。 其中还解释了与其他 Azure…...
3 redis实现一个消息中间件
使用list实现一个队列,可以从左侧入队,也可以从右侧入对 即可以从左侧读取,也可以从右侧读取 1、Lindex Lindex 命令用于通过索引获取列表中的元素 也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的…...
js添加dom到指定div之后,并给添加的dom类名,然后设置其样式,以及el-popover层级z-index过高问题解决。
遇到一个需求,Vue项目做一个表格,要求表头与表格内容分开,如下效果所示,表头与表格有个高度间隔边距(箭头所示),因为默认我们的el-table的表头与内容是一起的: 思路:通过querySelector获取el-table__header-wrapper元素,通过createElement创建一个div,通过 newElem…...
C语言结构体
#include <stdio.h> #include <string.h> #include <stdlib.h>//struct Student_s { // int num; // char name[20]; // char gender; // int age; // float Chinese; // float Math; // float English; // char addr[30]; //}; //最后的分号一定要写&#x…...
【Python大数据笔记_day10_Hive调优及Hadoop进阶】
hive调优 hive官方配置url: Configuration Properties - Apache Hive - Apache Software Foundation hive命令和参数配置 hive参数配置的意义: 开发Hive应用/调优时,不可避免地需要设定Hive的参数。设定Hive的参数可以调优HQL代码的执行效率,或帮助定位问…...
React经典初级错误
文章 前言错误场景问题分析解决方案后言 前言 ✨✨ 他们是天生勇敢的开发者,我们创造bug,传播bug,毫不留情地消灭bug,在这个过程中我们创造了很多bug以供娱乐。 前端bug这里是博主总结的一些前端的bug以及解决方案,感兴…...
C# System.Array.CopyTo() 和 System.Array.Clone() 有什么区别
System.Array.CopyTo() 和 System.Array.Clone() 是用于数组复制的两种不同方法,它们在实现和用途上有一些区别。 System.Array.CopyTo() 方法: CopyTo() 方法用于将数组的元素复制到另一个数组。它是 Array 类的实例方法,可以用于复制一个…...
Stable Diffusion 启动时 got an unexpected keyword argument ‘socket_options‘ 错误解决
Stable Diffusion 启动时 got an unexpected keyword argument socket_options 错误解决 问题解决方法 问题 Launching Web UI with arguments: Traceback (most recent call last):File "launch.py", line 48, in <module>main()File "launch.py"…...
CSS 文本属性篇
文字颜色 属性名:color作用:控制文字的颜色可选值: 1.颜色名 color: blue; 2.rgb或rgba color:rgb(132, 220, 254); color:rgba(132, 220, 254,0.5); 3.hex或hexa(十六进制) color:#0078d4; color:#0078d48b; 4.hsl或h…...
Activiti,Apache camel,Netflex conductor对比,业务选型
Activiti,Apache camel,Netflex conductor对比,业务选型 1.activiti是审批流,主要应用于人->系统交互,典型应用场景:请假,离职等审批 详情可见【精选】activti实际使用_activiti通过事件监听器实现的优势_记录点滴…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
