HttpRouter 源码分析(终章)
2023-12-30 04:26:05
回顾 HttpRouter 的设计思路和整体架构
HttpRouter 是一个高性能的 HTTP 路由器,它使用了一种称为“Radix Tree”的数据结构来存储路由信息。Radix Tree 是一种树形数据结构,它可以快速地查找字符串中的最长公共前缀。这使得 HttpRouter 能够非常快速地找到匹配请求 URL 的路由。
HttpRouter 的整体架构非常简单,它主要由以下几个部分组成:
- Radix Tree:用于存储路由信息的数据结构。
- TrieNode:Radix Tree 中的节点。
- TrieNodePool:TrieNode 的对象池。
- Handler:请求处理函数。
- Router:HttpRouter 的核心组件,负责路由请求到相应的 Handler。
源码分析
New
func New() *Router {
r := &Router{
wildcard: true,
RedirectTrailingSlash: true,
RedirectFixedPath: false,
HandleMethodNotAllowed: true,
NotFound: nil,
MethodNotAllowed: nil,
PanicHandler: nil,
Tree: &tree{},
Pool: &sync.Pool{New: func() interface{} { return &node{} }},
}
r.GET("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Welcome to HttpRouter")
}))
return r
}
New 函数是 HttpRouter 的构造函数,它创建一个新的 Router 实例。
Handle
func (r *Router) Handle(method, path string, handler http.Handler) {
if path[0] != '/' {
panic("path must begin with '/' in path '" + path + "'")
}
if method == "" {
panic("method must not be empty")
}
if handler == nil {
panic("handler must not be nil")
}
r.addRoute(method, path, handler)
}
Handle 函数用于添加一个新的路由。它接收三个参数:
- method:请求方法。
- path:请求路径。
- handler:请求处理函数。
addRoute
func (r *Router) addRoute(method, path string, handler http.Handler) {
if method == "*" {
method = "GET"
}
if len(method) > 0 {
method = strings.ToUpper(method)
}
if len(path) > 0 && path[0] != '/' {
path = "/" + path
}
root := r.Tree.Root()
if r.wildcard {
root.AddWildcard(handler)
}
r.Tree.AddRoute(method, path, handler)
}
addRoute 函数是 Handle 函数的内部实现,它将一个新的路由添加到 Radix Tree 中。
GET
func (r *Router) GET(path string, handler http.Handler) {
r.Handle("GET", path, handler)
}
GET 函数是 Handle 函数的一个简化版本,它专门用于添加一个新的 GET 路由。
POST
func (r *Router) POST(path string, handler http.Handler) {
r.Handle("POST", path, handler)
}
POST 函数是 Handle 函数的另一个简化版本,它专门用于添加一个新的 POST 路由。
PUT
func (r *Router) PUT(path string, handler http.Handler) {
r.Handle("PUT", path, handler)
}
PUT 函数是 Handle 函数的又一个简化版本,它专门用于添加一个新的 PUT 路由。
DELETE
func (r *Router) DELETE(path string, handler http.Handler) {
r.Handle("DELETE", path, handler)
}
DELETE 函数是 Handle 函数的最后一个简化版本,它专门用于添加一个新的 DELETE 路由。
ServeHTTP
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if r.RedirectTrailingSlash {
if req.URL.Path != "/" {
path := req.URL.Path
if path[len(path)-1] == '/' {
path = path[:len(path)-1]
}
http.Redirect(w, req, path, http.StatusMovedPermanently)
return
}
}
if r.RedirectFixedPath && req.URL.Path != req.URL.EscapedPath() {
pathEscaped := req.URL.EscapedPath()
if pathEscaped != "/" {
pathEscaped = pathEscaped[:strings.LastIndex(pathEscaped, "/")]
}
http.Redirect(w, req, pathEscaped, http.StatusMovedPermanently)
return
}
r.Find(req, w)
}
ServeHTTP 函数是 HttpRouter 的核心函数,它负责路由请求到相应的 Handler。
Find
func (r *Router) Find(req *http.Request, w http.ResponseWriter) {
method := req.Method
if method == "" {
method = "GET"
}
if len(method) > 0 {
method = strings.ToUpper(method)
}
path := req.URL.Path
if len(path) > 0 && path[0] != '/' {
path = "/" + path
}
root := r.Tree.Root()
if r.wildcard {
n := root.Child('*')
if n != nil {
n.handler(w, req)
return
}
}
n := r.Tree.MatchRoute(method, path)
if n != nil {
n.handler(w, req)
return
}
if r.NotFound != nil {
r.NotFound(w, req)
return
}
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
Find 函数是 ServeHTTP 函数的内部实现,它负责查找与请求匹配的路由。
panicHandler
func (r *Router) panicHandler(w http.ResponseWriter, r *http.Request, panicValue interface{}) {
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("X-Content-Type-Options", "nosniff")
if r.PanicHandler != nil {
r.PanicHandler(w, r, panicValue)
} else {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}
panicHandler 函数是 HttpRouter 的恐慌处理函数,它负责处理请求处理函数中的恐慌。
Wrap
func (r *Router) Wrap(f http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if !r.allowMethod(req.Method) {
if r.MethodNotAllowed != nil {
r.MethodNotAllowed(w, req)
} else {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
}
return
}
r.ServeHTTP(w, req)
})
}
Wrap 函数是 HttpRouter 的包装函数,它将一个普通的 HTTP Handler 包装成一个 HttpRouter 兼容的 Handler。
总结
至此,我们已经完成了对 HttpRouter 源码的分析。通过本次分析,我们不仅对 HttpRouter 的设计思路和整体架构有了更深入的了解,还对 HttpRouter 的具体实现细节有了更加深入的理解。希望本次分析能够对大家有所帮助。