Radix树实现的动态路由服务框架
【摘要】 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)