0%

http之golang gin 框架的路由算法

[TOC]

综述

todo… not good

gin 框架的路由,本质上是一个前缀树。每一种http method有一颗数,并且前缀树采用最长前缀来表示, 而不是简单的通过斜杠分隔。

注册

获取树的根节点

1
2
3
4
5
6
7
8
9
// 注意这里使用的是数组,在数据量很小的时候, 遍历数组肯定是比使用哈希表更高效的方式,由于http method 的方法就只有有限的几种类型,所以数组时更高效的选择。
func (trees methodTrees) get(method string) *node {
for _, tree := range trees {
if tree.method == method {
return tree.root
}
}
return nil
}

tree node

1
2
3
4
5
6
7
8
9
10
11
type node struct {
path string // 当前节点相对路径(与祖先节点的 path 拼接可得到完整路径)
indices string // 所有孩子节点的path[0]组成的字符串
children []*node // 孩子节点
handlers HandlersChain // 当前节点的处理函数(包括中间件)
priority uint32 // 当前节点及子孙节点的实际路由数量
nType nodeType // 节点类型
maxParams uint8 // 子孙节点的最大参数数量
wildChild bool // 孩子节点是否有通配符(wildcard)
fullPath string // 路由全路径
}

nType 有这几个值

1
2
3
4
5
6
const (
static nodeType = iota // 普通节点,默认
root // 根节点
param // 参数路由,比如 /user/:id
catchAll // 匹配所有内容的路由,比如 /article/*key
)

注册

处理请求

ServeHTTP

1
2
3
4
5
6
7
8
9
10
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request = req
c.reset()

engine.handleHTTPRequest(c)

engine.pool.Put(c)
}

寻找路由并处理动态参数

1
2
3
4
5
6
7
8
// getValue returns the handle registered with the given path (key). The values of
// wildcards are saved to a map.
// If no handle can be found, a TSR (trailing slash redirect) recommendation is
// made if a handle exists with an extra (without the) trailing slash for the
// given path.
func (n *node) getValue(path string, po Params, unescape bool) (value nodeValue) {

}

参考

gin 源码阅读(二)– 路由和路由组