HTTP框架修炼之道课程作业(作业4&作业5)
作业内容
- 为什么HTTP框架做要分层设计?分层设计有哪些优势与劣势。
- 现有开源社区HTTP框架有哪些优势与不足。
- 中间件还有没有其他实现方式?可以用伪代码说明。
- 完成基于前缀路由树的注册与查找功能?可以用伪代码说明。
- 路由还有没有其他的实现方式?
作业4
完成基于前缀路由树的注册与查找功能?可以用伪代码说明
基于前缀路由树的注册与查找功能是一种常见的路由匹配算法,用于在一个路由表中查找与给定请求路径匹配的路由。它的主要思想是使用一棵前缀树来存储所有的路由信息。
一个前缀树由一个根节点、若干个内部节点和若干个叶子节点组成。每个节点都有一个值,通常是一个字符,用来表示当前节点的名称。内部节点没有值,叶子节点的值则是路由对应的处理函数。
// 节点结构体
type Node struct {
Value string
Children map[string]*Node
Handler func(http.ResponseWriter, *http.Request)
}
// 前缀路由树结构体
type PrefixTree struct {
Root *Node
}
在注册路由时,我们将路由按照路径分割成多个“路由段”,然后将路由段依次添加到前缀树中。如果当前节点没有对应名称的子节点,我们就创建一个新节点,并将路由段的值作为新节点的值。如果该节点已经存在,则直接跳到该节点。
// 注册路由
func (t *PrefixTree) RegisterRoute(route string, handler func(http.ResponseWriter, *http.Request)) {
currentNode := t.Root
segments := strings.Split(route, "/")
for _, segment := range segments {
if _, ok := currentNode.Children[segment]; !ok {
newNode := &Node{
Value: segment,
Children: make(map[string]*Node),
}
currentNode.Children[segment] = newNode
currentNode = newNode
} else {
currentNode = currentNode.Children[segment]
}
}
currentNode.Handler = handler
}
在查找路由时,我们将请求路径按照路径分割成多个“路径段”,然后遍历前缀树,逐个匹配路径段,直到找到最后一个路径段为止。如果在匹配过程中,某个节点的子节点中没有与当前路径段匹配的节点,则说明该路径并不存在。如果匹配成功,则返回该节点的值,即对应的处理函数。
// 查找路由
func (t *PrefixTree) FindRoute(route string) func(http.ResponseWriter, *http.Request) {
currentNode := t.Root
segments := strings.Split(route, "/")
for _, segment := range segments {
if _, ok := currentNode.Children[segment]; ok {
currentNode = currentNode.Children[segment]
} else {
return nil // 路由不存在
}
}
return currentNode.Handler
}
在使用时,我们可以创建一个前缀路由树对象,然后注册路由,并传入对应的处理函数。之后根据请求路径查找对应的处理函数,并进行处理。
// 创建前缀路由树
prefixTree := &PrefixTree{Root: &Node{Value: ""}}
// 注册路由
prefixTree.RegisterRoute("/api/user", userHandler)
prefixTree.RegisterRoute("/api/product", productHandler)
prefixTree.RegisterRoute("/api/product/detail", productDetailHandler)
// 查找路由并调用对应的处理函数
handler := prefixTree.FindRoute("/api/user") // 返回 userHandler
handler(responseWriter, request) // 调用 userHandler 处理请求
handler = prefixTree.FindRoute("/api/product/detail") // 返回 productDetailHandler
handler(responseWriter, request) // 调用 productDetailHandler 处理请求
handler = prefixTree.FindRoute("/api/orders") // 返回 nil
作业5
路由还有没有其他的实现方式?
除了基于前缀路由树的实现方式,路由还可以使用正则表达式、哈希表等方式实现。下面简单介绍一下这几种方式。
- 正则表达式路由
使用正则表达式来匹配路由,常见的正则表达式匹配库有regexp、re等。在Go语言中,常用的正则表达式路由库有mux、httprouter等。正则表达式路由的优点是可以处理各种复杂的路由匹配需求,例如通配符、参数等。缺点是性能可能较差,因为需要进行正则表达式匹配,而正则表达式的匹配复杂度较高。
- 哈希表路由
使用哈希表(或字典)来存储路由和对应的处理函数。在Go语言中,常用的哈希表路由库有chi、gin等。哈希表路由的优点是查找速度快,而且可以实现快速的动态路由注册和删除。缺点是无法处理复杂的路由匹配需求,例如通配符、参数等。
- 其他路由实现方式
还有一些其他的路由实现方式,例如使用有限状态机(FSM)来匹配路由,或者使用有向无环图(DAG)来存储路由和对应的处理函数。这些实现方式具有一些特殊的优点和适用场景,但是相对于前缀路由树和正则表达式路由来说较为复杂,一般情况下不太常用。