Radix树实现的动态路由服务框架

举报
码乐 发表于 2025/03/16 09:42:53 2025/03/16
【摘要】 1 简介可以使用动态路由的web 迷你框架,本文使用Radix 树实现示例。Radix 树通过路径压缩和公共前缀合并,将 URL 路径映射为更紧凑的数据结构。对路径片段的匹配可以逐层深入,减少冗余节点。查询参数的匹配则依赖于键值哈希映射,时间复杂度更低,但不适合层级资源匹配。 2 实现示例如果服务需要 层级资源匹配 (如 /user/:id/posts/:postId),选择 动态路由。如...

1 简介

可以使用动态路由的web 迷你框架,本文使用Radix 树实现示例。

Radix 树通过路径压缩和公共前缀合并,将 URL 路径映射为更紧凑的数据结构。
对路径片段的匹配可以逐层深入,减少冗余节点。

查询参数的匹配则依赖于键值哈希映射,时间复杂度更低,但不适合层级资源匹配。

2 实现示例

如果服务需要 层级资源匹配 (如 /user/:id/posts/:postId),选择 动态路由。
如果是 可选筛选、排序参数 (如 /users?age=20),选择 查询参数。
Radix 树对路径匹配进行了路径压缩,性能比传统树结构更优。

    // Context 封装请求和响应
    type Context struct {
        Writer  http.ResponseWriter
        Request *http.Request
        Params  map[string]string
        index   int
        handlers []HandlerFunc
    }

    type HandlerFunc func(*Context)

    func (c *Context) JSON(status int, data string) {
        c.Writer.Header().Set("Content-Type", "application/json")
        c.Writer.WriteHeader(status)
        c.Writer.Write([]byte(data))
    }

    func (c *Context) Next() {
        c.index++
        for c.index < len(c.handlers) {
            c.handlers[c.index](c)
            c.index++
        }
    }

    // 路由节点
    type RadixNode struct {
        path     string
        handler  HandlerFunc
        children map[string]*RadixNode
        isParam  bool
        paramKey string
    }

    func NewRadixNode() *RadixNode {
        return &RadixNode{children: make(map[string]*RadixNode)}
    }

    func (n *RadixNode) Insert(path string, handler HandlerFunc) {
        if path == "" {
            n.handler = handler
            return
        }
        parts := strings.SplitN(path, "/", 2)
        part := parts[0]
        re := regexp.MustCompile(`^:(\w+)$`)
        if matches := re.FindStringSubmatch(part); len(matches) > 0 {
            part = ":"
            n.isParam = true
            n.paramKey = matches[1]
        }

        if _, exists := n.children[part]; !exists {
            n.children[part] = NewRadixNode()
        }

        remaining := ""
        if len(parts) > 1 {
            remaining = parts[1]
        }
        n.children[part].Insert(remaining, handler)
    }

    func (n *RadixNode) Search(path string, params map[string]string) HandlerFunc {
        if path == "" && n.handler != nil {
            return n.handler
        }
        parts := strings.SplitN(path, "/", 2)
        part := parts[0]
        remaining := ""
        if len(parts) > 1 {
            remaining = parts[1]
        }

        if child, exists := n.children[part]; exists {
            return child.Search(remaining, params)
        }

        if n.isParam {
            params[n.paramKey] = part
            if child, exists := n.children[":"]; exists {
                return child.Search(remaining, params)
            }
        }

        return nil
    }

    // Web框架引擎
    type Engine struct {
        route *RadixNode
    }

    func NewEngine() *Engine {
        return &Engine{route: NewRadixNode()}
    }

    func (e *Engine) GET(path string, handler HandlerFunc) {
        e.route.Insert(path, handler)
    }

    func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
        params := make(map[string]string)
        handler := e.route.Search(req.URL.Path, params)
        if handler != nil {
            c := &Context{Writer: w, Request: req, Params: params, handlers: []HandlerFunc{handler}}
            c.Next()
        } else {
            http.NotFound(w, req)
        }
    }

    func main() {
        r := NewEngine()

        r.GET("/ping", func(c *Context) {
            c.JSON(200, `{"message": "pong"}`)
        })

        r.GET("/user/:id", func(c *Context) {
            id := c.Params["id"]
            c.JSON(200, fmt.Sprintf(`{"user_id": "%s"}`, id))
        })

        http.ListenAndServe(":8080", r)
        fmt.Println("Server is running at :8080")
    }

3 小结

通过 路径分片匹配 来匹配路径。
Radix 树会将路径 /user/:id 分解成节点:
/user/ 固定前缀
:id 动态通配符节点

匹配时依次匹配路径片段,如果遇到 :id,将路径片段赋值给参数。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。