Go 1.22中HTTP包更新

每当我在网上遇到讨论或被问到使用哪个包在 Go 中创建 HTTP 服务器时,我的答案都是一致的。这实际上取决于您计划构建的 HTTP 服务的复杂性,但我始终建议net/http从标准包开始

Go 语言拥有令人印象深刻的标准库,net/http是其实力的一个突出例子。随着 1.22 版本的发布,它变得更好了。

标准库问题是什么?
我是使用net/http简单服务的大力倡导者。然而,我知道,随着您的项目不断发展,您开始处理多个端点(每个端点都有自己的参数集并需要处理各种 HTTP 方法),事情可能会变得有点混乱。曾经整洁的 HTTP 处理程序开始变得像一个杂乱的房间,充满了重复的代码,并且变得有点难以导航。

func  handlerUser (w http.ResponseWriter, r *http.Request) {
    userID := getPathValue(r)
    ...
     switch r.Method {
     case  "GET" :
         
// 处理 GET 请求
        fmt.Fprintf(w,
"Hello, % s!" , name)
     case  
"POST" :
         
// 处理 POST 请求
    case  
"PUT" :
         
// 处理 PUT 请求
    default :
         
// 处理其他 HTTP 方法或响应错误
        http.Error(w,
"Unsupported HTTP method" , http.StatusMethodNotAllowed)
    }
}

现在,在管理单个端点的各种 HTTP 方法时,您可能会发现自己渴望像 Chi 或 Echo 这样简单的框架。这些软件包允许你为每种 HTTP 方法指定特定的处理程序,从而简化代码。不过,坚持使用标准的 net/http 包意味着你的处理程序本身需要容纳所有允许的方法,这可能会变得有点繁琐,如上图所示。

此外,处理路径参数还带来了另一层复杂性。如果没有更复杂框架的内置支持,你就只能采用变通方法。使用 http.StripPrefix 或使用 strings.TrimPrefix 手动修剪路径前缀等技巧就变得很有必要。这种方法有点临时抱佛脚,需要额外的代码和精力,才能完成使用专门路由库时相对简单的工作。

1.22版本的变化
处理多个 HTTP 方法和提取路径参数可能会让人觉得有点麻烦,但 Go 1.22 已经解决了这个问题。最新更新为 ServeMux 处理程序引入了增强的路由功能,使这些任务不再令人头疼。

现在,你可以在注册处理程序时直接指定 HTTP 方法,如 POST 或 GET。更令人印象深刻的是在 URL 模式中引入了通配符。这意味着您可以定义类似 /orders/{id} 这样的模式来匹配 URL 路径的特定段落,而这一功能以前需要第三方路由器或一些自定义解析逻辑。

从这些路径段中读取实际值也很简单。只需使用新的 Request.PathValue 方法即可。这一新增功能大大简化了动态路由所需的代码,使更复杂的网络应用程序的开发更顺畅、更直观。

mux.HandleFunc("GET /orders", func(w http.ResponseWriter, r *http.Request) {"GET /orders", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(
"Get all orders"))
})
mux.HandleFunc(
"POST /orders", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(
"Create an order"))
})
mux.HandleFunc(
"GET /orders/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue(
"id")
    fmt.Fprintf(w,
"Get order with id: %s", id)
})
mux.HandleFunc(
"PUT /orders/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue(
"id")
    fmt.Fprintf(w,
"Update order with id: %s", id)
})
...

测试端点变得更容易了。

$ curl localhost:8080/orders8080/orders
Get all orders
$ curl -X POST localhost:8080/orders
Create an order
$ curl -X PUT localhost:8080/orders/2
Update order with id: 2

不过,并非每个端点都允许使用每种方法。如果您尝试使用不支持的方法,比如本例中的 DELETE:

$ curl -X DELETE localhost:8080/orders/2
Method Not Allowed

您将得到明确的回复:方法不允许。该响应可帮助您快速了解您试图执行的操作不允许该端点执行。

新的 {$} 功能
此外,新的通配符功能(以 {$} 标记)改变了 URL 模式的匹配方式,可以精确到尾部的斜线。在过去,像"/"这样的通配符就像一个 "万金油",可以拦截任何以"/"开头且没有定义其他通配符的路径。因此,"/"和"/this/does/not/exist "会无意中出现在同一个地方。

以下是一些开发人员使用的简单变通方法,可以同时优雅地管理主页和未识别的路径:

mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {"/", func(w http.ResponseWriter, req *http.Request) {
        if req.URL.Path !=
"/" {
                http.NotFound(w, req)
                return
        }
        fmt.Fprintf(w,
"Welcome to the home page!")
})


有了新的 {$} 功能,精确匹配就变得简单易行了。下面是使用方法:

mux.HandleFunc("/{$}", func(w http.ResponseWriter, r *http.Request) {"/{$}", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(
"Welcome to the home page!"))
})