当前位置: 首页 > news >正文

go web框架 gin-gonic源码解读01————Engine

go web框架 gin-gonic源码解读01————Engine


gin-gonic是go语言开发的轻量级web框架,性能优异,代码简洁,功能强大。有很多值得学习的地方,最近准备把这段时间学习gin的知识点,通过engine,context,router,middleware几篇博客文章总结总结。

而Engine是gin框架最核心的结构体。
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default()
type Engine struct {
// ... 略
}

为什么gin需要设计一个Engine结构体?
因为gin框架依赖于go本身的 net/http 包来提供http服务。 net/http 包的http服务可以用以下方式快速的启动:

type mHandle struct {
}func (i mHandle ) ServeHTTP(w http.ResponseWriter, req *http.Request) {w.Write([]byte("Hello"))
}func HttpRun() {// mHandle{} 实现了 net/http中的Handler接口http.Handle("/", mHandle{})http.ListenAndServe(":9999", nil)
}
// net/http中的Handler接口
// type Handler interface {
//	 ServeHTTP(ResponseWriter, *Request)
// }

而我们gin框架的Engine也实现了一个net/http包的Handler接口。当是gin既然是依赖老的net/http为什么大家不直接使用net/http,而是需要使用gin呢,那是因为net/http在大多数情况下只支持静态路由,而且不能很好的支持动态路由,对中间件的开发也不友好,也不能很好的支持http模版的返回,所以大多数时候我们更倾向于使用集成了这些功能的gin,并且gin的代码量很少,简直是小而美。

type Engine struct {// ... 略// 对象池,这里用于存放gin.Context对象,减少内存分配,降低 GC 压力。pool	sync.Pool// 路由树trees  methodTrees
}// ServeHTTP conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {// Context是gin框架为了更方便的处理http的请求与响应,(即w http.ResponseWriter, req *http.Request)// 而对进行的封装,每次接受到http请求都需要封装一下Context结构体,交由下一步代码执行,Context在后续的博客中会有详细的介绍c := engine.pool.Get().(*Context)c.writermem.reset(w)c.Request = reqc.reset()// 将请求交于逻辑函数执行engine.handleHTTPRequest(c)// 执行完了进行归还engine.pool.Put(c)
}// 逻辑函数,这里来解析请求的url,然后路由匹配该路径需要执行的方法
func (engine *Engine) handleHTTPRequest(c *Context) {// 获取请求方法GET,POST..httpMethod := c.Request.Method// 获取urlrPath := c.Request.URL.Pathunescape := false// 如果地址存在原始地址,则使用原始地址if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {rPath = c.Request.URL.RawPathunescape = engine.UnescapePathValues}if engine.RemoveExtraSlash {// cleaenpPath 函数作用类似于filepath.Clean(),是为了获取最短有效urlrPath = cleanPath(rPath)}// Find root of the tree for the given HTTP method// engine.trees中存放是gin框架的路由树,它采用前缀树结构来搞笑的存储各类路由	// 后续的博客会对路由树有更为详细的介绍,这里就简单介绍一下。t := engine.treesfor i, tl := 0, len(t); i < tl; i++ {// 路由树的第一层孩子节点都是请求方法,如GET,POST。。。if t[i].method != httpMethod {continue}root := t[i].root// Find route in tree// 查找请求的url是否有对应的url路由配置value := root.getValue(rPath, c.params, c.skippedNodes, unescape)if value.params != nil {c.Params = *value.params}// value.handlers存储的就是该路由的逻辑处理方法if value.handlers != nil {c.handlers = value.handlersc.fullPath = value.fullPath// c.Next是gin框架调用handlers与各类中间件的一种便捷的方式,后续讲中间件的时候会重点介绍。c.Next()// 处理完了,写入响应的头文件c.writermem.WriteHeaderNow()return}// 执行到这里了说明value.handlers == nil,这里判断是不是重定向请求,然后进行重定向处理if httpMethod != http.MethodConnect && rPath != "/" {if value.tsr && engine.RedirectTrailingSlash {redirectTrailingSlash(c)return}// 实在找不到,就尝试修复你的url看看能不能找到合适的路由来处理if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {return}}break}// HandleMethodNotAllowed 这个配置如果开启,并且没有找到合适的路由来处理该请求,就会尝试别的method 会不会有可以解析该请求的路由if engine.HandleMethodNotAllowed {for _, tree := range engine.trees {// 相同method的上面已经找过了,这里continueif tree.method == httpMethod {continue}// 到别的请求方法下面嚯嚯if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {c.handlers = engine.allNoMethodserveError(c, http.StatusMethodNotAllowed, default405Body)return}}}// 啥招都没有了,调用统一的失败处理函数,响应该请求c.handlers = engine.allNoRouteserveError(c, http.StatusNotFound, default404Body)
}
http://www.lryc.cn/news/102702.html

相关文章:

  • windows版docker部署springcloud项目
  • 探索工程机械远程控制新纪元:Intewell-Hyper II震撼发布!
  • DM8 DSC集群实时主备搭建
  • 配置IPv4 over IPv6隧道示例
  • 在中国区部署日志通2.0
  • centos下安装jdk
  • 【HDFS】LocatedBlocks、LocatedBlock、LocatedStripedBlock、ExtendedBlock类分析
  • Oracle 19c 报ORA-704 ORA-01555故障处理---惜分飞
  • D356周赛复盘:滑动窗口+三元问题思路
  • ETHERNET/IP 转ETHERCAT连接倍福和欧姆龙PLC的配置方法
  • Git分布式版本控制工具和GitHub(一)--简介
  • 【Terraform学习】Terraform-AWS部署快速入门(快速入门)
  • 力扣75——深度优先搜索
  • 【C++初阶】C++基础(上)——C++关键字、命名空间、C++输入输出、缺省参数、函数重载
  • 代码随想录训练营Day55动态规划part15|392.判断子序列|115.不同的子序列
  • Linux下安装RabbitMQ教程
  • 如何加强Mysql安全,请给出可行的具体措施
  • 创造自己的宠物医院预约服务小程序,步骤详解
  • MACOM EDI 需求分析
  • 使用Spring Boot AOP实现日志记录
  • 图像中不规则物体的长轴与短轴:OpenCV实现指南
  • C/C++开发,opencv与qt结合播放视频
  • 磁共振图像处理中 fft1c 和 ifft1c 函数的 Python 实现
  • 阿里云国际站香港地域服务器访问延迟丢包的原因及解决方法
  • GULI PART.1
  • NetApp FAS2750 和 FAS2820:适用于分布式企业和从远程到核心的 FAS
  • 剑指YOLOv8改进最新MPDIoU损失函数:超越现有多种G/D/C/EIoU,23年7月首发论文,高效准确的边界框回归的损失
  • SQL-每日一题【1070. 产品销售分析 III】
  • 为何押注AI大模型的微软云,业绩增速反而不如谷歌云?
  • CDN加速服务的工作原理