go 1.22 增强 http.ServerMux 路由能力

之前

server

go 复制代码
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("Received request:", r.URL.Path)
		fmt.Fprintf(w, "Hello, client! You requested: %s\n", r.URL.Path)
	})

	log.Println("Server is running on http://localhost:8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe error: ", err)
	}
}

client

go 复制代码
func main() {
	url := "http://localhost:8080/some-path"

	// 创建HTTP GET请求
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal("HTTP GET error: ", err)
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal("Error reading response body: ", err)
	}

	fmt.Println("Response from server:", string(body))
}

模式匹配优先级

如果两个模式重叠,那么更精确的模式优先。

如果 P1 符合 P2 请求的一个(严格)子集,P1 就比 P2 更精细

如果两者都不更具体,那么模式就会发生冲突

例外:

如果两个模式发生冲突,而其中一个有 HOST ,另一个没有,那么有 HOST 的模式优先。

example.com/ 比 / 更精细

因为第一个仅匹配主机 example.com 的请求,而第二个匹配任何请求

GET / 比 / 更精细

因为第一个仅匹配 GET 和 HEAD 请求,而第二个匹配任何请求

/b/{bucket}/o/default 比 /b/{bucket}/o/{noun} 更精细

第一个仅匹配第四个元素是文字 "default" 的路径,而在第二个中,第四个元素可以是任何内容

匹配方法

模式匹配将支持以 HTTP 方法开头,后跟空格,如 GET /demo 或 GET demo.com/

带有方法的模式仅用于匹配具有该方法的请求

Go1.22 起,http.ServeMux 可以这么写:

go 复制代码
mux.HandleFunc("POST /demo/create", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "demo create")
})

mux.HandleFunc("GET /demo/update", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "demo update")
})

通配符

模式匹配将支持 {name} 或 {name...}

例如:/b/{bucket}/o/{objectname...}

该名称必须是有效的 Go 标识符和符合完整路径元素的标准

它们前面必须有斜杠,后面必须有斜杠或字符串末尾

例如:/b_{bucket} 不是有效的通配模式

Go1.22 起,http.ServeMux 可以这么写:

go 复制代码
mux.HandleFunc("/demo/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")
    fmt.Fprint(w, "id %s", id)
})

mux.HandleFunc("/demo/{path...}", func(w http.ResponseWriter, r *http.Request) {
    path := r.PathValue("path")
    fmt.Fprint(w, "path %s", path)
})

示例

server

go 复制代码
func main() {
	http.HandleFunc("/demo/{id}", func(w http.ResponseWriter, r *http.Request) {
		id := r.PathValue("id")
		fmt.Fprintf(w, "id %s\n", id)
		fmt.Fprintf(w, "Hello, client! You requested: %s\n", r.URL.Path)
	})

	log.Println("Server is running  on /demo/x")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe error: ", err)
	}
}

client

go 复制代码
func client() {
	url := "http://localhost:8080/demo/2?name=cucc"

	// 创建HTTP GET请求
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal("HTTP GET error: ", err)
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal("Error reading response body: ", err)
	}

	fmt.Println("Response from server:\n", string(body))
}
相关推荐
凉凉的知识库2 小时前
什么是 HTTP Keep-Alive?一文讲清连接复用机制
网络协议·http·面试
wlsh152 小时前
HTTP 协议
http
Wang's Blog2 小时前
Go-Zero 项目开发19:基于 Kafka 的异步消息存储与转发实战
golang·kafka
小莫分享3 小时前
sshw:用交互搜索和 Web 配置高效管理 SSH Server
linux·运维·golang·开源·ssh
名字还没想好☜3 小时前
Go 结构体内存对齐:调整字段顺序,同样的字段省下 40% 内存
开发语言·后端·golang·go·内存对齐
FfHUCisI3 小时前
sync.Mutex 互斥锁
golang
牛奔13 小时前
Go 如何打印调试深层或嵌套的结构体
开发语言·后端·golang
geovindu13 小时前
go: Iterative Algorithms
开发语言·后端·算法·golang·迭代算法
kite012115 小时前
Go语言Map深度解析与最佳实践
开发语言·后端·golang
巨量HTTP20 小时前
Python爬虫动态换IP实战,彻底解决IP403封禁、限流问题(附完整代码)
爬虫·python·tcp/ip·http