Go1.22来了!还需要HTTP框架吗?

2024-04-24 22:34:58 浏览数 (1)

在Go语言原生的HTTP路由中大家是否注意到过功能不是很完善,比如需要硬编码区分GET还是POST请求,在Go 1.22中对Go的HTTP路由做了一定程度的增强,这都要源于一个提案:net/http: enhanced ServeMux routing(https://github.com/golang/go/issues/61410)

在这个提案中提到了Go语言的路由应该变为:

代码语言:go复制
GET example.com/

或者:

代码语言:go复制
GET /foo

再或者:

代码语言:go复制
GET example.com/foo

可以抽象为以下语义分配路由:

代码语言:shell复制
[METHOD] [HOST]/[PATH]

解释:

  • METHOD:要为其执行分配的处理程序的请求方式,如GET、PUT、POST等。
  • HOST:要使用处理程序的主机名。
  • PATH:要将处理程序映射到的 Request 路径。

提案中还提到,其中一种模式比另一种模式更具体:

  • example.com// 更具体,因为第一个仅匹配与主机 example.com 的请求,而第二个匹配任何请求。
  • GET // 更具体,因为第一个只匹配 GET 和 HEAD 请求,而第二个匹配任何请求。
  • HEAD /GET / 更具体,因为第一个只匹配 HEAD 请求,而第二个同时匹配 GET 和 HEAD 请求。
  • /b/{bucket}/o/default/b/{bucket}/o/{noun} 更具体,因为第一个元素仅匹配第四个元素是文本“默认”的路径,而在第二个元素中,第四个元素可以是任何元素。

下面我们用代码对比下:

在1.22版本前的Go语言原生HTTP路由中,如果要区分GET和POST请求,我们需要这样:

代码语言:go复制
func OriginalHttpService() {
	mux := http.NewServeMux()

	mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			_, _ = w.Write([]byte("Hello, This is GET method. [Go]"))
		case http.MethodPost:
			_, _ = w.Write([]byte("Hello, This is POST method. [Go]"))
		}
	})

	_ = http.ListenAndServe(":8801", mux)
}

如果不使用原生的HTTP包,我们可以用Gin框架,它就变成了这样:

代码语言:go复制
func GinHttpService() {
	engine := gin.Default()

	engine.GET("/hello", func(c *gin.Context) {
		c.JSON(http.StatusOK, "Hello, This is GET method. [Gin]")
	})
	engine.POST("/hello", func(c *gin.Context) {
		c.JSON(http.StatusOK, "Hello, This is POST method. [Gin]")
	})

	_ = engine.Run(":8802")
}

如果到了Go1.22,我们就可以不使用框架实现这个功能:

代码语言:go复制
func Go22NewHttpService() {
	mux := http.NewServeMux()

	mux.HandleFunc("GET /hello", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte("Hello, This is GET method. [Go 1.22]"))
	})
	mux.HandleFunc("POST /hello", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte("Hello, This is POST method. [Go 1.22]"))
	})

	_ = http.ListenAndServe(":8803", mux)
}

是不是觉得优雅了许多~

除此之外,新版本还支持了Restful风格的API,比如:

代码语言:go复制
func Go22RestfulApi() {
	mux := http.NewServeMux()

	mux.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) {
		name := r.PathValue("name")
		resp := fmt.Sprintf("Hello %s, This is GET method.", name)
		_, _ = w.Write([]byte(resp))
	})

	_ = http.ListenAndServe(":8803", mux)
}

在Path重叠的情况下,Go官方还提供了优先级的解释,比如 /posts/latest/posts/{id}在同一个HTTP服务中,会以更具体的作为优先,显然 /posts/latest/posts/{id}更具体,可以参考:https://go.dev/blog/routing-enhancements会有更详细的说明

我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

0 人点赞