返回

HttpRouter 源码分析(终章)

后端

回顾 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 的具体实现细节有了更加深入的理解。希望本次分析能够对大家有所帮助。