<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>

          mux功能完備的 Go 路由器

          聯(lián)合創(chuàng)作 · 2023-09-20 05:58

          mux 是對 http.ServeMux 的擴(kuò)展,添加正則路由等功能。

          - 路由參數(shù);
          - 支持正則表達(dá)式作為路由項(xiàng)匹配方式;
          - 攔截正則表達(dá)式的行為;
          - 自動(dòng)生成 OPTIONS 請求處理方式;
          - 自動(dòng)生成 HEAD 請求處理方式;
          - 根據(jù)路由反向生成地址;
          - 任意風(fēng)格的路由,比如 discuz 這種不以 / 作為分隔符的;
          - 分組路由,比如按域名,或是版本號等;
          - CORS 跨域資源的處理;
          - 支持中間件;
          - 自動(dòng)生成 OPTIONS * 請求;
          - 靜態(tài)文件系統(tǒng);

          import "github.com/issue9/middleware/v4/compress"
          import "github.com/issue9/mux/v5"
          
          c := compress.New()
          
          router := mux.NewRouter("")
          router.Middlewares().Append(c)
          router.Get("/users/1", h).
              Post("/login", h).
              Get("/pages/{id:\\d+}.html", h). // 匹配 /pages/123.html 等格式,path = 123
              Get("/posts/{path}.html", h).    // 匹配 /posts/2020/11/11/title.html 等格式,path = 2020/11/11/title
          
          // 統(tǒng)一前綴路徑的路由
          p := router.Prefix("/api")
          p.Get("/logout", h) // 相當(dāng)于 m.Get("/api/logout", h)
          p.Post("/login", h) // 相當(dāng)于 m.Get("/api/login", h)
          
          // 對同一資源的不同操作
          res := p.Resource("/users/{id:\\d+}")
          res.Get(h)   // 相當(dāng)于 m.Get("/api/users/{id:\\d+}", h)
          res.Post(h)  // 相當(dāng)于 m.Post("/api/users/{id:\\d+}", h)
          res.URL(map[string]string{"id": "5"}) // 構(gòu)建一條基于此路由項(xiàng)的路徑:/users/5
          
          http.ListenAndServe(":8080", router)

          ## 語法

           

          路由參數(shù)采用大括號包含,內(nèi)部包含名稱和規(guī)則兩部分:`{name:rule}`,
          其中的 name 表示參數(shù)的名稱,rule 表示對參數(shù)的約束規(guī)則。
          
          name 可以包含 `-` 前綴,表示在實(shí)際執(zhí)行過程中,不捕獲該名稱的對應(yīng)的值,
          可以在一定程序上提升性能。
          
          rule 表示對參數(shù)的約束,一般為正則或是空,為空表示匹配任意值,
          攔截器一欄中有關(guān) rule 的高級用法。以下是一些常見的示例。
          
          ```text
          /posts/{id}.html                  // 匹配 /posts/1.html
          /posts-{id}-{page}.html           // 匹配 /posts-1-10.html
          /posts/{path:\\w+}.html           // 匹配 /posts/2020/11/11/title.html
          /tags/{tag:\\w+}/{path}           // 匹配 /tags/abc/title.html
          ```
          
          ### 路徑匹配規(guī)則
          
          可能會(huì)出現(xiàn)多條記錄與同一請求都匹配的情況,這種情況下,
          系統(tǒng)會(huì)找到一條認(rèn)為最匹配的路由來處理,判斷規(guī)則如下:
          
          1. 普通路由優(yōu)先于正則路由;
          1. 攔截器優(yōu)先于正則路由;
          1. 正則路由優(yōu)先于命名路由;
          
          比如:
          
          ```text
          /posts/{id}.html              // 1
          /posts/{id:\\d+}.html         // 2
          /posts/1.html                 // 3
          
          /posts/1.html      // 匹配 3
          /posts/11.html     // 匹配 2
          /posts/index.html  // 匹配 1
          ```
          
          路徑的匹配是以從左到右的順序進(jìn)行的,父節(jié)點(diǎn)不會(huì)因?yàn)闆]有子節(jié)點(diǎn)匹配而擴(kuò)大自己的匹配范圍,
          比如 `/posts/{id}-{page:digit}.html` 可以匹配 `/posts/1-1.html`,但無法匹配
          `/posts/1-1-1.html`,雖然理論上 `1-1-` 也能匹配 `{id}`,但是 `1-` 已經(jīng)優(yōu)先匹配了,
          在子元素找不到的情況下,并不會(huì)將父元素的匹配范圍擴(kuò)大到 `1-1-`### 路由參數(shù)
          
          通過正則表達(dá)式匹配的路由,其中帶命名的參數(shù)可通過 `GetParams()` 獲取:
          
          ```go
          import "github.com/issue9/mux/v5"
          
          params := mux.GetParams(r)
          
          id, err := params.Int("id")
           // 或是
          id := params.MustInt("id", 0) // 在無法獲取 id 參數(shù)時(shí)采用 0 作為默認(rèn)值返回
          ```
          
          ## 高級用法
          
          ### 分組路由
          
          可以通過匹配 `group.Matcher` 接口,定義了一組特定要求的路由項(xiàng)。
          
          ```go
          // server.go
          
          import "github.com/issue9/mux/v5"
          import "github.com/issue9/mux/v5/group"
          
          m := group.New()
          
          def := mux.NewRouter("default", false, nil)
          m.AddRouter(group.NewPathVersion("version-key", "v1"), def)
          def.Get("/path", h1)
          
          host := mux.NewRouter("host", false, nil)
          m.AddRouter(group.NewHosts("*.example.com"), host)
          host.Get("/path", h2)
          
          http.ListenAndServe(":8080", m)
          
          // client.go
          
          // 訪問 h2 的內(nèi)容
          r := http.NewRequest(http.MethodGet, "https://abc.example.com/path", nil)
          r.Do()
          
          // 訪問 h1 的內(nèi)容
          r := http.NewRequest(http.MethodGet, "https://other_domain.com/v1/path", nil)
          r.Do()
          ```
          
          ### 攔截器
          
          正常情況下,`/posts/{id:\d+}` 或是 `/posts/{id:[0-9]+}` 會(huì)被當(dāng)作正則表達(dá)式處理,
          但是正則表達(dá)式的性能并不是很好,這個(gè)時(shí)候我們可以通過在 `NewRouter` 傳遞 `Interceptor` 進(jìn)行攔截:
          
          ```go
          import "github.com/issue9/mux/v5"
          
          func digit(path string) bool {
              for _, c := range path {
                  if c < '0' || c > '9' {
                      return false
                  }
              }
              return len(path) > 0
          }
          
          // 路由中的 \d+ 和 [0-9]+ 均采用 digit 函數(shù)進(jìn)行處理,不再是正則表達(dá)式。
          r := mux.NewRouter("", mux.Interceptor(digit, "\\d+", "[0-9]+"))
          ```
          
          這樣在所有路由項(xiàng)中的 `[0-9]+` `\\d+` 將由 `digit` 函數(shù)處理,
          不再會(huì)被編譯為正則表達(dá)式,在性能上會(huì)有很大的提升。
          通過該功能,也可以自定義一些非正常的正則表達(dá)這式,然后進(jìn)行攔截,比如:
          
          ```text
          /posts/{id:digit}/.html
          ```
          
          如果不攔截,最終傳遞給正則表達(dá)式,可能會(huì)出現(xiàn)編譯錯(cuò)誤,通過攔截器可以將 digit 合法化。
          目前提供了以下幾個(gè)攔截器:
          
          - InterceptorDigit 限定為數(shù)字字符,相當(dāng)于正則的 `[0-9]`- InterceptorWord 相當(dāng)于正則的 `[a-zA-Z0-9]`- InterceptorAny 表示匹配任意非空內(nèi)容;
          
          用戶也可以自行實(shí)現(xiàn) `InterceptorFunc` 作為攔截器。具體可參考 <https://pkg.go.dev/github.com/issue9/mux/v5#Interceptor>
          
          ### CORS
          
          CORS 不再是以中間件的形式提供,而是通過 NewRouter 直接傳遞有關(guān) CORS 的配置信息,
          這樣可以更好地處理每個(gè)地址支持的請求方法。
          
          OPTIONS 請求方法由系統(tǒng)自動(dòng)生成。
          
          ```go
          import "github.com/issue9/mux/v5"
          
          r := mux.NewRouter("name" ,AllowedCORS) // 任意跨域請求
          
          r.Get("/posts/{id}", nil)     // 默認(rèn)情況下, OPTIONS 的報(bào)頭為 GET, OPTIONS
          
          http.ListenAndServe(":8080", m)
          
          // client.go
          
          // 訪問 h2 的內(nèi)容
          r := http.NewRequest(http.MethodGet, "https://localhost:8080/posts/1", nil)
          r.Header.Set("Origin", "https://example.com")
          r.Do() // 跨域,可以正常訪問
          
          
          r = http.NewRequest(http.MethodOptions, "https://localhost:8080/posts/1", nil)
          r.Header.Set("Origin", "https://example.com")
          r.Header.Set("Access-Control-Request-Method", "GET")
          r.Do() // 預(yù)檢請求,可以正常訪問
          ```
          
          ### 靜態(tài)文件
          
          可以使用 `FileServer` 與命名參數(shù)相結(jié)合的方式實(shí)現(xiàn)靜態(tài)文件的訪問:
          
          ```go
          r := NewRouter("")
          r.Get("/assets/{path}", FileServer(os.DirFS("/static/"), "path", "index.html", nil))
          ```
          
          ### 中間件
          
          mux 本身就是一個(gè)實(shí)現(xiàn)了 [http.Handler](https://pkg.go.dev/net/http#Handler) 接口的中間件,
          所有實(shí)現(xiàn)官方接口 `http.Handler` 的都可以附加到 mux 上作為中間件使用。
          
          mux 本身也提供了對中間件的管理功能,同時(shí) [middleware](https://github.com/issue9/middleware) 提供了常用的中間件功能。
          
          ```go
          import "github.com/issue9/middleware/v4/compress"
          
          c := compress.New(log.Default(), "*")
          
          r := mux.NewRouter("")
          
          // 添加中間件
          r.Middlewares().Append(c.Middleware)
          ```
          
          
          

          ## 性能

          <https://caixw.github.io/go-http-routers-testing/> 提供了與其它幾個(gè)框架的對比情況。

          瀏覽 16
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報(bào)
          <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>
                  久久人妻人人操 | 爱情岛论坛www成人网站 | 小早怜子一区二区三区 | 天天插网站| 久久艹大香蕉 |