Gin(四)给 Engine 摸摸骨

内容纲要

前情提要

Gin(三)给 Engine 看看相

前文我们主要看了 Engine 的请求处理流程,其中重点研究了 engine.ServerHTTP 和 engine. handleHTTPRequest 两个函数方法的处理流程。其中出现了几个比较重要的问题还没研究:

  • trees
  • node

现在,我们来揭开它们的面纱。

trees

跟踪源码得知:

  1. trees 是 Engine 的一个变量
  2. trees 的类型是 methodTrees
    • type methodTrees []methodTree
      • type methodTree struct {
        method string
        root   *node
        }

可以看出,trees 本质上是一个包含两个变量(method、root)的结构体的数组。

node

node 结构体

从 trees 的类型里面,我们可以看到有个 root 变量,它的类型是 node,这就是 trees 与 node 之间的关系。下面我们来看看 node 到底是什么。

// node 源码
type node struct {
    path      string
    indices   string
    children  []*node
    handlers  HandlersChain
    priority  uint32
    nType     nodeType
    maxParams uint8
    wildChild bool
    fullPath  string
}

这个类型信息量还是挺大的,从其中几个变量能看出不少问题:

  • children []*node
    • 这是一个包含自身类型(node)的指针列表
      • 可见这可以是个树状结构
  • handlers HandlersChain
    • 之前的研究中也出现过无数次的 handler 这个词
      • 可以猜到这个变量即用来指向每个请求的处理函数的
  • path string
    • 请求路径,显而易见
  • nType nodeType
    • node 类型(从源码中可以看到有:static、root、param、catchAll 这么几个枚举常量)
      • 其它的先不说,但可以联想到前面的 trees 里的 root 应该就是对应的这个

node 操作函数(方法)

node 结构体总共有一下 5 个操作函数。从它们的注释,我们对 node 的功能也能有一个比较清晰的认识了。

// 增加给定子级的优先级,必要时重新排序
func (n *node) incrementChildPrio(pos int) int {...}

// (原注释并不是这么解释的,这是我初步看过源码后总结的)
// 将请求处理方法绑定的节点(node)添加到节点树里
// 如果节点树是空的,则作为 root 节点
// addRouter 的调用方是 Engine 的爸爸 RouteGroup(下章我们就详细看看这个是什么)
func (n *node) addRoute(path string, handlers HandlersChain) {...}

// (作为内部函数被 addRoute 调用,主要功能就是指向插入节点的操作)
func (n *node) insertChild(numParams uint8, path string, fullPath string, handlers HandlersChain) {...}

// 返回给点路径的节点信息(句柄等)
// (前文中的 trees 那个 for 循环中有对 root 节点进行 getValue 的操作,即是这个函数)
func (n *node) getValue(path string, po Params, unescape bool) (value nodeValue) {...}

// 对路径进行不区分大小写的查找,并可以修复末尾斜杆问题,返回校正的路径
// (跟 Engine 的对应参数进行配合使用)
func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) (ciPath []byte, found bool) {...}

小结

经过 3 篇文章的分析,我们大概已经理清了一个 Gin 服务从创建到请求处理的整个基本流程。

  1. 实例化一个 Engine 结构体
  2. 通过 net/http 库把 Engine 实例和 http.Server 进行绑定
  3. net/http 启动监听服务
  4. 接到请求将请求转发到 Engine 的 ServeHTTP 接口,并调用 handleHTTPRequest 进行请求处理
  5. handleHTTPRequest 对 path 进行处理,并通过查询 trees 的节点,得到请求 handlers
  6. handlers 被交给 Context 进行真正的 handler 调用并返回请求结果
Tags: , ,

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注