beego路由实现原理
树形结构+递归算法实现路由的注册与匹配:
1 数据结构:
// 树节点结构
type Tree struct { //search fix route first fixrouters map[string]*Tree //if set, failure to match fixrouters search then search wildcard wildcard *Tree //if set, failure to match wildcard search leaves []*leafInfo }
// 叶子节点结构
type leafInfo struct {
// names of wildcards that lead to this leaf. eg, ["id" "name"] for the wildcard ":id" and ":name" wildcards []string // if the leaf is regexp regexps *regexp.Regexp // 方法结构信息 runObject interface{} }
2 简化算法
func (t *Tree) addseg(segments []string, route interface{}, wildcards []string, reg string) { if len(segments) == 0 {
// 路径为空,添加叶子节点 t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: filterCards, regexps: regexp.MustCompile("^" + reg + "$")}) } else {
// 解析路径 seg := segments[0] // 取路径前面一段 iswild, params, regexpStr := splitSegment(seg) // 解析该段是否为正则段,并提取参数名 // 为正则节点
if iswild {
if t.wildcard == nil {
t.wildcard = NewTree()
}
// xxx 省略N多代码
t.wildcard.addseg(segments[1:], route, append(wildcards, params...), reg+regexpStr)
} else {
// 非正则节点
subTree, ok := t.fixrouters[seg]
if !ok {
subTree = NewTree()
t.fixrouters[seg] = subTree
}
subTree.addseg(segments[1:], route, wildcards, reg)
}
}
}
实例解析
1 路由注册
2 路由匹配
固定路由: /r1/r2 如图1, 路径段依次与树节点匹配。匹配完刚好存在无参数的叶子节点,表明匹配成功
正则路由: /r1/r4/r3 如图2, r1 <=> r1节点 r4无匹配节点故对应:id正则节点(并将r4保存做实参后与参数名对应,以便获得参数值), r3 <=> r3, 到叶子节点对比参数名与实参个数是否相等,相等匹配成功
高级正则路由:如图3,固定路径段匹配并去掉,剩下未匹配路径重新组装与叶子节点保存的正则串进行正则匹配,并去除对应实参值
ps:beego路由以方法来创建路径树。如存在GET,PUT等等路径树