Golang中如何使用net/http实现动态URL或正则表达式路由
Golang中如何使用net/http实现动态URL或正则表达式路由
我不想使用 Gorilla/mux,因为有人说它的性能较慢,而这正是我想要避免的。
那么,如何仅使用 net/http 包(不使用 gorilla mux)来实现 "page/{pageTitle}/{pageId}/HelloWorld" 这样的动态或正则表达式 URL 呢?
我想我会采纳你另一个回答中提到的 HttpRouter,它实际上比内置的多路复用器更快。非常感谢!
更多关于Golang中如何使用net/http实现动态URL或正则表达式路由的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用正则表达式(regexp)的路由器性能较慢,开源的主流路由器有 httprouter、chi、mux。
性能耗时:httprouter 3,chi 14,mux 100+。
在一般项目中,不必过分关注路由器的性能。与其他操作相比,路由器消耗的资源较少。
在路由器的实现中,有基于基数树(radix)和基于 for 循环的两种实现方式。与 for 循环系列相比,基数树系列天然具有高性能。此外,正则表达式(regexp)操作在验证过程中会消耗大量资源。
我的路由器示例:https://github.com/eudore/erouter。
中文实现文档:https://github.com/eudore/eudore/wiki/4.5.1-eudore-router-radix
在标准库 net/http 中实现动态路由,可以通过解析请求路径并手动匹配模式来实现。以下是一个示例,展示如何实现类似 "page/{pageTitle}/{pageId}/HelloWorld" 的路由:
package main
import (
"fmt"
"net/http"
"strings"
)
// 定义路由处理函数类型
type routeHandler func(http.ResponseWriter, *http.Request, map[string]string)
// 路由结构体
type Route struct {
pattern string
handler routeHandler
}
// 路由器
type Router struct {
routes []Route
}
// 注册路由
func (r *Router) HandleFunc(pattern string, handler routeHandler) {
r.routes = append(r.routes, Route{pattern: pattern, handler: handler})
}
// 实现 http.Handler 接口
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
for _, route := range r.routes {
if params, ok := r.match(route.pattern, req.URL.Path); ok {
route.handler(w, req, params)
return
}
}
http.NotFound(w, req)
}
// 路径匹配函数
func (r *Router) match(pattern, path string) (map[string]string, bool) {
patternParts := strings.Split(pattern, "/")
pathParts := strings.Split(path, "/")
if len(patternParts) != len(pathParts) {
return nil, false
}
params := make(map[string]string)
for i, patternPart := range patternParts {
if strings.HasPrefix(patternPart, "{") && strings.HasSuffix(patternPart, "}") {
// 提取参数名
paramName := patternPart[1 : len(patternPart)-1]
params[paramName] = pathParts[i]
} else if patternPart != pathParts[i] {
return nil, false
}
}
return params, true
}
// 示例处理函数
func pageHandler(w http.ResponseWriter, req *http.Request, params map[string]string) {
pageTitle := params["pageTitle"]
pageId := params["pageId"]
fmt.Fprintf(w, "Page Title: %s, Page ID: %s", pageTitle, pageId)
}
func main() {
router := &Router{}
// 注册动态路由
router.HandleFunc("page/{pageTitle}/{pageId}/HelloWorld", pageHandler)
// 启动服务器
http.ListenAndServe(":8080", router)
}
这个实现支持基本的动态参数提取。对于更复杂的正则表达式匹配,可以修改 match 函数来支持正则模式。例如:
import "regexp"
type Route struct {
pattern *regexp.Regexp
handler routeHandler
}
func (r *Router) HandleRegex(pattern string, handler routeHandler) {
compiled := regexp.MustCompile(pattern)
r.routes = append(r.routes, Route{pattern: compiled, handler: handler})
}
func (r *Router) matchRegex(pattern *regexp.Regexp, path string) (map[string]string, bool) {
matches := pattern.FindStringSubmatch(path)
if matches == nil {
return nil, false
}
params := make(map[string]string)
for i, name := range pattern.SubexpNames() {
if i != 0 && name != "" {
params[name] = matches[i]
}
}
return params, true
}
使用正则表达式路由:
router.HandleRegex(`^/page/(?P<pageTitle>[^/]+)/(?P<pageId>[^/]+)/HelloWorld$`, pageHandler)
这种方法避免了第三方依赖,同时提供了动态路由功能。性能方面,由于减少了抽象层,通常比使用完整路由库更快。

