Gin框架源码解析

news2024/9/24 17:18:26

概要

目录

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方法对应的路由树。

  1. Priority(优先级):每个树级别上的子节点都按照优先级排序,其中优先级就是在子节点上注册的句柄数量。优点:优先匹配被大多数路由路径包含的节点(更快速定位)、最长路径可以优先匹配(成本补偿)。
  2. Handle: Get每个路由对应的实现函数。*<数字> 表示Handle处理函数的内存地址。

URL具有层级结构,并且都是有限的字符组,所以有很多常见的前缀。这样是的我们很容易将路由简化为更小的问题。

路由器为每种请求方法管理一颗单独的树

一、路由树节点

type node struct {
   // 节点路径,比如上面的s,earch,和upport
	path      string
	// 和children字段对应, 保存的是分裂的分支的第一个字符
	// 例如search和support, 那么s节点的indices对应的"eu"
	// 代表有两个分支, 分支的首字母分别是e和u
	indices   string
	// 儿子节点
	children  []*node
	// 处理函数链条(切片)
	handlers  HandlersChain
	// 优先级,子节点、子子节点等注册的handler数量
	priority  uint32
	// 节点类型,包括static, root, param, catchAll
	// static: 静态节点(默认),比如上面的s,earch等节点
	// root: 树的根节点
	// catchAll: 有*匹配的节点
	// param: 参数节点
	nType     nodeType
	// 路径上最大参数个数
	maxParams uint8
	// 节点是否是参数节点,比如上面的:post
	wildChild bool
	// 完整路径
	fullPath  string
}

二、请求方法树

        每一个HTTP method都对应一颗radix树,我们注册路由的时候都会调用addRoute函数。函数含义我们可以看到在注册路由的时候都是先根据请求方法获取对应的树,也就是gin框架会为每一个请求方法创建一颗对应的树。只不过需要注意一个细节是gin框架中请求方法对应树关系并不是使用map而是使用的切片,engine.trees的类型是methodThrees

type methodTree struct {
	method string
	root   *node
}

type methodTrees []methodTree  // slice

func (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种,用切片存储和查询效率足够。只需要做出一次性内存申请即可。

三、路由注册以及匹配

        路由注册函数:

  1. addRoute函数:将具有给定句柄的节点添加到路径中。不是并发安全的函数。
  2. insertChild函数:根据path本身进行分割,将/分开的部分分别作为节点保存,形成一颗树结构。参数匹配中的 : 和 *  的区别是,前者是匹配一个字段,后者是匹配后面所有的路径。

        路由匹配:


func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  // 这里使用了对象池
	c := engine.pool.Get().(*Context)
  // 这里有一个细节就是Get对象后做初始化
	c.writermem.reset(w)
	c.Request = req
	c.reset()

	engine.handleHTTPRequest(c)  // 我们要找的处理HTTP请求的函数

	engine.pool.Put(c)  // 处理完请求后将对象放回池子
}


func (engine *Engine) handleHTTPRequest(c *Context) {
	// 根据请求方法找到对应的路由树
	t := engine.trees
	for 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.handlers
			c.Params = value.params
			c.fullPath = value.fullPath
			c.Next()  // 执行函数链条
			c.writermem.WriteHeaderNow()
			return
		}
	

	c.handlers = engine.allNoRoute
	serveError(c, http.StatusNotFound, default404Body)
}

        路由匹配是由节点的GetValue方法实现的。getValue根据给定的路径返回nodeValue值,里面保存的处理函数和匹配到的路径参数数据。如果找不到任何处理函数,会尝试TSR(尾随斜杠重定向)。 

中间件含义

        中间件是指处理HTTP请求的函数或组件,通常用于在请求到达目标处理程序之前或之后执行一些处理逻辑。中间件在Go语言中经常被使用,因为它提供了一种可扩展和可重用的机制,用于处理身份验证、授权、日志记录、错误处理等常见的Web应用程序需求。

        中间件在Go语言主要是因为它提供了一种灵活、可扩展和可重用的机制,用于处理Web应用程序中的各种需求和逻辑。

        中间件优势:

  1. 函数式编程思想:Go语言支持函数式编程风格,而中间件提供了一种将函数作为参数传递并在请求处理过程中进行组合和调用的机制。使得代码更加模块化和可重用性。
  2. 请求处理流程的可扩展性:中间件允许开发人员将请求处理流程分解为多个独立的函数或组件,这些 组件可以按照特定的顺序组合和调用。这种可扩展性使得开发人员可以轻松的添加、移除或替换中间件,以满足特定的应用程序需求。
  3. 前后置处理逻辑:中间件可以在请求到达目标处理程序之前或之前执行一些处理逻辑,例如身份验证、日志记录、错误处理等。这种机制使得开发人员可以轻松的请求处理过程中添加前后置处理逻辑,而无需修改现有的代码。
  4. 社区支持和普及。

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()中断整个调用链条,从当前函数返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1228075.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java SE】循环一些基本练习

判定一个数字是否是素数 public class Test {public static int is_sushu(int n) {if(n 1) {return 0;}int i ;for (i 2; i < Math.sqrt(n); i) {if(n % i 0 ) {break;}}if (i > n) {return 1;}return 0;}public static void main(String[] args) {Scanner scanner …

报错:HikariPool-1 - Exception during pool initialization.

问题发现&#xff1a; 原本可以运行的springboot2项目突然无法运行且报错&#xff0c;HikariPool-1 - Exception during pool initialization。 问题分析&#xff1a; 观察报错信息发现是JDBC连接失败&#xff0c;进而搜索HikariPool-1&#xff0c;搜索得知应该是applicatio…

Java中锁的深入理解

目录 对象头的理解 Monitor&#xff08;锁&#xff09; 锁类型 偏向锁 偏向锁的优化机制 轻量级锁 重量级锁 对象头的理解 在32位Java虚拟机中普通对象的对象头是占用8个字节&#xff0c;其中4个字节为Mark Word。用来存储对象的哈希值&#xff0c;对象创建后在JVM中的…

Polygon zkEVM协议治理、升级及其流程

1. 引言 随着Polygon社区开发者和内部团队的测试深入&#xff0c;当前版本的Polygon zkEVM不可避免地需更新和某些升级。 为激励开发者对Polygon zkEVM做battle-test&#xff0c;已启动了bug-bounty&#xff1a; Rewards by Threat Level 由于zk-Rollup生态系统还处于萌芽阶…

python 的 import 机制

引言 对于初学 python&#xff0c;或多或少在 import 一个 module 时遇到过 ImportError: attempted relative import with no known parent package 这样的错误信息。对于初学 python&#xff0c;遇到这样的问题是因为在执行 python xxx.py 程序时&#xff0c;xxx.py 程序中 …

〖大前端 - 基础入门三大核心之JS篇㊳〗- DOM访问元素节点

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

基于springboot实现应急救援物资管理系统项目【项目源码】计算机毕业设计

基于springboot实现应急救援物资管理系统演示 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&a…

Centos7 重置 Root 密码

Centos7 重置 Root 密码 1.启动服务器2.编辑启动项3.修改密码4.重新登陆 1.启动服务器 启动服务器后&#xff0c;不要直接进入系统&#xff0c;在开机页面按键盘【E】 2.编辑启动项 按【E】后进入如下页面&#xff0c;并按向下箭头&#xff0c;找到如图位置&#xff0c;添加如…

慢日志查询

概述 MySQL的慢查询日志是MySQL提供的一种日志记录&#xff0c;它用来记录在MySQL中响应时间超过阀值的语句&#xff0c;具体指运行时间超过 long_query_time 值的SQL&#xff0c;则会被记录到慢查询日志中&#xff0c;ong_query_time 的默认值为 10&#xff0c;意思是运行10S…

JAVA多线程(5)

JAVA多线程(5) 线程安全问题概述 卖票问题分析 单窗口卖票 一个窗口(单线程)卖100张票没有问题 单线程程序是不会出现线程安全问题的 多个窗口卖不同的票 3个窗口一起卖票,卖的票不同,也不会出现问题 多线程程序,没有访问共享数据,不会产生问题 多个窗口卖相同的票 3个窗口…

QT下使用QChart绘制曲线

目录 头文件内容构造函数AddSeries方法UpdateSeries方法AppendSeriesData方法SetLegendVisiableSetRubberBandCPP内容测试函数 需要用到的头文件&#xff1a; #include <QtCharts/QChart> #include <QtCharts/QChartView> #include <QtCharts/QValueAxis> #…

大数据安全 测试

测试1、用户 hive/1.common2.hadoop.fql.comLEXIN.COM 和 nn/1.common2.hadoop.fql.com 分别对 Hive 进行查询 &#xff08;1&#xff09;HDFS 配置 vim /usr/local/fqlhadoop/hadoop/conf/core-site.xml <property><name>hadoop.proxyuser.hive.hosts</name&g…

16. @PostConstruct注解和开关原理(验证码开关、IP开关)

1►PostConstruct注解 PostConstruct是java自带的注解&#xff0c;会在java项目启动的时候先执行下面的方法 2►开关原理&#xff08;验证码开关&#xff09; 我们的项目具有验证码功能&#xff0c;旧版不支持关闭&#xff0c;新版已经支持关闭了。 我们打开页面“参数管…

go-zero微服务的使用

一、入门案例 1、使用goland创建一个工程 2、新建一个user.proto syntax "proto3";package user; // 这个地方表示生成的go的包名叫user option go_package "./user";message UserInfoRequest {int64 userId 1; }message UserInfoResponse {int64 user…

2024年csdn最新最全的Postman接口测试: postman实现参数化

什么时候会用到参数化 比如&#xff1a;一个模块要用多组不同数据进行测试 验证业务的正确性 Login模块&#xff1a;正确的用户名&#xff0c;密码 成功&#xff1b;错误的用户名&#xff0c;正确的密码 失败 postman实现参数化 在实际的接口测试中&#xff0c;部分参数…

【机器学习】特征工程:特征选择、数据降维、PCA

各位同学好&#xff0c;今天我和大家分享一下python机器学习中的特征选择和数据降维。内容有&#xff1a; &#xff08;1&#xff09;过滤选择&#xff1b;&#xff08;2&#xff09;数据降维PCA&#xff1b;&#xff08;3&#xff09;sklearn实现 那我们开始吧。 一个数据集中…

第93步 深度学习图像分割:PSPNet建模

基于WIN10的64位系统演示 一、写在前面 本期&#xff0c;我们继续学习深度学习图像分割系列的另一个模型&#xff0c;PSPNet。 二、PSPNet简介 &#xff08;1&#xff09;金字塔池化模块 (Pyramid Pooling Module) PSPNet的核心是其金字塔池化模块&#xff0c;该模块能够捕…

2024年csdn最新最全面的fiddler教程【1】

Fiddler简介 Fiddler是比较好用的web代理调试工具之一&#xff0c;它能记录并检查所有客户端与服务端的HTTP/HTTPS请求&#xff0c;能够设置断点&#xff0c;篡改及伪造Request/Response的数据&#xff0c;修改hosts&#xff0c;限制网速&#xff0c;http请求性能统计&#xff…

ERR:Navicat连接Sql Server报错

错误信息&#xff1a;报错&#xff1a;未发现数据源名称并且未指定默认驱动程序。 原因&#xff1a;Navicat没有安装Sqlserver驱动。 解决方案&#xff1a;在Navicat安装目录下找到sqlncli_x64.msi安装即可。 一键安装即可。 Navicat链接SQL Server配置 - MarchXD - 博客园 …

【腾讯云 HAI域探秘】——即时职场生存指南小游戏以及【自行搭建Stable Diffusion图片AI绘制 | ChatGLM2-6B AI进行智能对话 | Pytorch2.0 AI框架视频处理】

利用HAI的ChatGLM2 6B做一个即时对话小游戏 ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本&#xff0c;在保留了初代模型对话流畅、部署门槛较低等众多优秀特性的基础之上&#xff0c;ChatGLM2-6B 引入了更强大的性能、更长的上下文、更高效的推理&#xff0c;…