<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          不看就落后了,Go 1.22 中更好的http router

          共 6546字,需瀏覽 14分鐘

           ·

          2024-03-23 10:30

          很多人為了使用Go web中更好的路由,會使用第三方的庫 httproutergorilla/mux等。在明年的春節(jié)左右發(fā)布的Go 1.22中,Go官方終于對標準庫中的http.ServeMux下手了,對它的功能進行了優(yōu)化,終于可以拋棄第三方庫了。

          一個令人興奮的提案預計將在Go 1.22中實現—— 增強標準庫net/http包中默認HTTP服務多路復用器的模式匹配能力。

          現有的多路復用器( http.ServeMux )提供了基本的路徑匹配,但除此之外沒有太多。這導致了一堆的第三方庫實現了更強大的功能。

          Go 1.22中的新多路復用器將通過提供高級匹配能力來顯著彌合與第三方庫的差距。在這篇短文中,我將快速介紹新的多路復用器(mux)。我還將給出REST服務器的示例,并比較新的標準庫muxgorilla/mux的性能。

          使用新的mux

          如果你曾經在Go中使用過第三方 mux/router(比如gorilla/mux),那么使用新的標準mux將是簡單而熟悉的。從閱讀它的文檔開始——它簡短絲滑。

          讓我們來看幾個基本用法示例。我們的第一個示例演示了mux的一些新模式匹配功能:

                
                  package main
                
                
                  import (
                
                
                    "fmt"
                
                
                    "net/http"
                
                
                  )
                
                
                  
                    
          func main() { mux := http.NewServeMux() mux.HandleFunc("GET /path/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "got path\n") })
          mux.HandleFunc("/task/{id}/", func(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") fmt.Fprintf(w, "handling task with id=%v\n", id) })
          http.ListenAndServe("localhost:8090", mux) }

          經驗豐富的Go程序員會立即注意到兩個新功能:

          • 在第一個處理程序中,HTTP method(在本例中為GET)被明確指定為模式的一部分。這意味著該處理程序將只觸發(fā)以/path/開頭的路徑的GET請求,而不觸發(fā)其他HTTP method。

          • 在第二個處理程序中,第二個路徑組件 - {id}中有一個通配符,這是以前不支持的。通配符將匹配單個路徑組件,然后處理程序可以通過請求的PathValue方法訪問匹配的值。


          由于Go 1.22尚未發(fā)布,你可以使用gotip運行此示例。請參閱完整的代碼示例以及運行此程序的完整說明。讓我們來試試這個服務器:

                
                  $ gotip run sample.go
                
              

          在一個單獨的終端中,我們可以發(fā)出一些curl調用來測試它:

                
                  $ curl localhost:8090/what/
                
                
                  404 page not found
                
                
                  
                    
          $ curl localhost:8090/path/ got path
          $ curl -X POST localhost:8090/path/ Method Not Allowed
          $ curl localhost:8090/task/f0cd2e/ handling task with id=f0cd2e

          請注意,服務器如何拒絕對/path/的POST請求,同時允許(curl的默認值)GET請求。還要注意,當請求匹配時,id通配符是如何被分配一個值的。我再次鼓勵您查看新ServeMux的文檔。您將了解其他功能,如將尾隨路徑與帶有{id}的通配符匹配,路徑以{$}結尾的嚴格匹配以及其他規(guī)則。

          提案中特別注意不同模式之間的潛在沖突。請考慮此設置:

                
                  mux := http.NewServeMux()
                
                
                  mux.HandleFunc("/task/{id}/status/", func(w http.ResponseWriter, r *http.Request) {
                
                
                          id := r.PathValue("id")
                
                
                          fmt.Fprintf(w, "handling task status with id=%v\n", id)
                
                
                  })
                
                
                  mux.HandleFunc("/task/0/{action}/", func(w http.ResponseWriter, r *http.Request) {
                
                
                          action := r.PathValue("action")
                
                
                          fmt.Fprintf(w, "handling task 0 with action=%v\n", action)
                
                
                  })
                
              

          假設服務器收到 /task/0/status/ 的請求——它應該轉到哪個處理程序?兩者都匹配!因此,新的 ServeMux 文檔仔細地描述了模式的優(yōu)先級規(guī)則以及潛在的沖突。如果發(fā)生沖突,注冊會panic。事實上,對于上面的例子,我們得到了如下內容:

                
                  panic: pattern "/task/0/{action}/" (registered at sample-conflict.go:14) conflicts with pattern "/task/{id}/status/" (registered at sample-conflict.go:10):
                
                
                  /task/0/{action}/ and /task/{id}/status/ both match some paths, like "/task/0/status/".
                
                
                  But neither is more specific than the other.
                
                
                  /task/0/{action}/ matches "/task/0/action/", but /task/{id}/status/ doesn't.
                
                
                  /task/{id}/status/ matches "/task/id/status/", but /task/0/{action}/ doesn't.
                
              


          該信息詳細且有用。如果我們在復雜的注冊方案中遇到沖突(尤其是當模式在源代碼中的多個位置注冊時),這些細節(jié)會非常有用。

          用新的mux實現服務器

          REST Servers in Go series的REST服務器使用幾種不同的方法為Go中的任務/待辦事項列表應用程序實現了一個簡單的服務器。第1部分從標準庫開始,第2部分使用gorilla/mux路由器重新實現了相同的服務器。

          現在是再次實現它的好時機,但有了Go 1.22的增強mux;將該解決方案與使用gorilla/mux的解決方案進行比較將特別有趣。

          此項目的完整代碼可在此處獲得。讓我們看看幾個有代表性的代碼示例,從模式注冊開始:

                
                  mux := http.NewServeMux()
                
                
                  server := NewTaskServer()
                
                
                  
                    
          mux.HandleFunc("POST /task/", server.createTaskHandler) mux.HandleFunc("GET /task/", server.getAllTasksHandler) mux.HandleFunc("DELETE /task/", server.deleteAllTasksHandler) mux.HandleFunc("GET /task/{id}/", server.getTaskHandler) mux.HandleFunc("DELETE /task/{id}/", server.deleteTaskHandler) mux.HandleFunc("GET /tag/{tag}/", server.tagHandler) mux.HandleFunc("GET /due/{year}/{month}/{day}/", server.dueHandler)

          就像在gorilla/mux示例中一樣,這里我們使用特定的HTTP method將請求(具有相同路徑)路由到不同的處理程序;使用舊的http.ServeMux這樣的匹配器就必須轉到同一個處理程序,然后由該處理程序根據該方法決定要做什么。

          讓我們看看其中一個處理程序:

                
                  func (ts *taskServer) getTaskHandler(w http.ResponseWriter, req *http.Request) {
                
                
                    log.Printf("handling get task at %s\n", req.URL.Path)
                
                
                  
                    
          id, err := strconv.Atoi(req.PathValue("id")) if err != nil { http.Error(w, "invalid id", http.StatusBadRequest) return }
          task, err := ts.store.GetTask(id) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return }
          renderJSON(w, task) }

          它從req.PathValue("id")中提取ID值。類似于Gorilla方法;然而,由于我們沒有正則表達式指定{id}只匹配整數,因此我們必須注意strconv.Atoi返回的錯誤。

          總之,最終結果與第2部分中使用gorilla/mux的解決方案非常相似。與普通的標準庫方法相比,處理程序的方式要好得多,因為mux現在可以進行更復雜的路由,而不會將許多路由決策留給處理程序本身。

          結論

          “我應該使用哪個router庫?”一直是Go初學者的常見問題。我相信在Go 1.22發(fā)布后,這個問題的常見答案會發(fā)生變化,因為許多人會發(fā)現新的標準庫 mux足以滿足他們的需求,而無需求助于第三方軟件包。

          其他人會堅持熟悉的第三方庫,這完全沒關系。像gorilla/mux這樣的路由器仍然提供比標準庫更多的功能;除此之外,許多Go程序員選擇了像Gin這樣的輕量級框架,它提供了一個路由器,但也提供了用于構建web后端的額外工具。

          總而言之,這對所有Go用戶來說無疑是一個積極的變化。無論人們是使用第三方軟件包還是堅持使用標準庫,讓標準庫更有能力對整個社區(qū)來說都是一個積極的方面。

          翻譯自Better HTTP server routing in Go 1.22。

          推薦閱讀:

          我是如何實現Go性能5倍提升的?

          「GoCN酷Go推薦」我用go寫了魔獸世界登錄器?

          Go區(qū)不大,創(chuàng)造神話,科目三殺進來了

          Go 1.22新特性前瞻

          這些流行的K8S工具,你都用上了嗎 ?


          想要了解Go更多內容,歡迎掃描下方??關注公眾號, 回復關鍵詞 [實戰(zhàn)群]   ,就有機會進群和我們進行交流



          分享、在看與點贊Go  c29be9e15b7622ca57555675c0b9ca10.webp
          瀏覽 190
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青娱乐AV伊人 | 大香蕉A片 | 久热精品免费 | 免费操逼网站直接入看泡芙视频 | 少妇大战黑人无套A片 |