Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gee-web项目中 路由注册顺序,导致的Bug #64

Open
FormalYou opened this issue Nov 21, 2022 · 3 comments
Open

gee-web项目中 路由注册顺序,导致的Bug #64

FormalYou opened this issue Nov 21, 2022 · 3 comments

Comments

@FormalYou
Copy link

func TestGetRoute(t *testing.T) {
	r := newRouter()
	r.addRoute("GET", "/", nil)
	r.addRoute("GET", "/hello/:id", nil)
	r.addRoute("GET", "/hello/b/c", nil)
	n, ps := r.getRoute("GET", "/hello/21/c")
	fmt.Printf("n: %v\n", n)  // n: node{pattern=/hello/b/c, part=c, isWild=false}
	fmt.Printf("ps: %v\n", ps)//ps: map[]
}

我们期望得到 n == nil, ps == nil , 但实际上却匹配到了静态路由 pattern=/hello/b/c.

由于注册顺序导致的 路由树可以简化为:
[0] root: path: /
[1] path: hello
[2] path: :id pattern : "/hello/:id"
[3] path: c pattern : "hello/b/c"

主要原因为 先注册的 路由为 /hello/:id , 后注册的路由为 /hello/b/c , 在查找时,没有返回 nil, 源代码如下:

func (n *node) matchChild(part string) *node {
	for _, child := range n.children {
        if child.part == part || child.isWild {  // false,  true
            // 在查找 part为 :id 这一层时, 直接返回了child 
			return child
		}
	}
	return nil
}
func (n *node) insert(pattern string, parts []string, height int) {
	if len(parts) == height {
		n.pattern = pattern
		return
	}

    part := parts[height]
    child := n.matchChild(part) // 由于返回的不是 nil , 而是  node.part == ":id" 这个节点。
	if child == nil {
		child = &node{part: part, isWild: part[0] == ':' || part[0] == '*'}
		n.children = append(n.children, child)
	}
    
	child.insert(pattern, parts, height+1)
}

要想达到预期 结果 n == nil, ps == nil , 就只能修改注册顺序。

先注册静态路由, 确保 matchChildren(part string) []*node  方法返回的切片 包含 child.part="b" 的这个节点。
r.addRoute("GET", "/hello/b/c", nil)
r.addRoute("GET", "/hello/:id", nil)
@JmyFilm
Copy link

JmyFilm commented Mar 15, 2023

insert 路由时的查找没有区分 partisWild ,应该在查找 part 不存在后再查找 isWild == true 的节点。
并且在 getRouter 时也需如此。

@GuiQuQu
Copy link

GuiQuQu commented Jun 25, 2023

在trie树建立的时候,是不区分:lang,*filepath还是a这三种中,给你的pattern怎么给的,你的树就怎么建,在查找的时候存在区别,当遇到:lang这种node的时候,寻找接下来可以扩展的子节点时,可以匹配任意的字符串,*filepath也是这样

@intyouss
Copy link

matchChild方法仅使用在insert插入时,我认为插入时无需区分p, :lang,*filepath是否isWild,可全盘接收,因此删除matchChild方法中child.isWild判断,可以修复这个顺序Bug。因为只有在search中使用matchChildren方法时才需要区分是否isWild来使用模糊匹配。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants