router.md - maoxiaoyue/hypgo GitHub Wiki
Router Package (pkg/router)
router 套件為 HypGo 實現了核心的路由分發機制。它基於高效的基數樹(Radix Tree)實作,擁有極快的路由比對速度,支援動態參數擷取與萬用字元配對,同時將路由群組管理整合在內,大幅簡化大型應用的 API 結構組織。
主要特色
- 零配置的高效能 Radix Tree: 自動化建立前綴樹進行路由檢索,執行速度遠勝一般基於 Regular Expression 的配對方式。
- 支援 RESTful 參數與萬用字元: 如
:id(名稱配對)、*filepath(萬用配對)。 - 內建記憶體快取 (LRU Route Cache): 若啟動時啟用,可以快取頻繁造訪的路由解析結果,使極高併發的路由比對效能再提升一個量級。
- 靈活的中間件與群組 (Group): 透過路由群組管理特定前綴的路由,並且能夠為全域或是特定的 Group 插入中介軟體(Middleware)。
- 嚴格或寬鬆的斜線處理 (Strict Slash): 可配置是否將
/path與/path/視作同一路徑並自動重新導向。 - 無縫整合 HTTP/3: 提供
EnableHTTP3機制讓 HTTP/3 與 QUIC 原生整合進路由的支援中。
基礎使用
初始化一個路由器並加入簡單的路徑:
package main
import (
"github.com/maoxiaoyue/hypgo/pkg/context"
"github.com/maoxiaoyue/hypgo/pkg/router"
)
func main() {
// 使用預設配置建立路由器
r := router.New()
// 基礎的 GET / POST
r.GET("/ping", func(c *context.Context) {
c.String(200, "pong")
})
r.POST("/submit", func(c *context.Context) {
c.String(200, "Submitted!")
})
// 在 main 裡面搭配 Http Server 啟動 (由 pkg/server 負責)
}
路由參數配對
存取由 :name 或 *action 定義的路徑參數:
// 匹配 /user/alice, /user/bob 等
r.GET("/user/:name", func(c *context.Context) {
name := c.Param("name")
c.String(200, "Hello %s", name)
})
// 匹配 /files/js/main.js 或 /files/css/style.css
r.GET("/files/*filepath", func(c *context.Context) {
path := c.Param("filepath")
c.String(200, "Requested file path: %s", path)
})
路由群組 (Group)
透過路由群組,能很方便的將不同業務邏輯切割開來:
api := r.NewGroup("/api/v1")
{
users := api.NewGroup("/users")
{
users.GET("/", listUsers) // /api/v1/users/
users.GET("/:id", getUser) // /api/v1/users/:id
users.POST("/", createUser) // /api/v1/users/
}
orders := api.NewGroup("/orders")
{
orders.GET("/", listOrders) // /api/v1/orders/
orders.GET("/:id", getOrder) // /api/v1/orders/:id
}
}
全域與群組中間件
使用 Use 可以在不同層級掛載 hypcontext.HandlerFunc:
// 全域套用:所有經過此路由器的請求都會先經過 Middleware1, Middleware2
r.Use(Middleware1, Middleware2)
// 單獨掛載:僅掛載於 api 群組
api := r.NewGroup("/api/v1")
api.Use(AuthMiddleware)
api.GET("/secure", secureHandler) // 必須經過 AuthMiddleware 才會執行
客製化配置
router.New 也開放以函數式選項進行詳細設定:
opts := []router.RouterOption{
router.WithCache(1000), // 啟用 LRU Route Cache,快取 1000 條結果
router.WithStrictSlash(true), // 嚴格區分結尾斜線
router.WithMethodNotAllowed(true), // 自動捕捉並回應 405 Method Not Allowed
}
r := router.New(opts...)
Schema-first 路由(AI 協作)
除了傳統的路由註冊,Router 支援 Schema() 方法,讓路由攜帶 metadata(輸入/輸出型別、描述、標籤),供 AI 理解 API 行為、Manifest 生成與 Contract Testing 使用:
import "github.com/maoxiaoyue/hypgo/pkg/schema"
// 定義帶 metadata 的路由
r.Schema(schema.Route{
Method: "POST",
Path: "/api/users",
Summary: "建立使用者",
Tags: []string{"users"},
Input: CreateUserRequest{},
Output: UserResponse{},
Responses: map[int]schema.ResponseSchema{
201: {Description: "User created"},
400: {Description: "Invalid input"},
},
}).Handle(createUserHandler)
Group 也支援 Schema,會自動加上 basePath 前綴:
api := r.NewGroup("/api/v1")
api.Schema(schema.Route{
Method: "GET",
Path: "/products",
Summary: "取得商品列表",
}).Handle(listProductsHandler)
// → 自動註冊為 GET /api/v1/products
Schema 路由與傳統路由可並存,完全向後相容。
路由資訊查詢
透過 Routes() 取得所有已註冊的路由資訊(含 handler 函式名稱):
for _, route := range r.Routes() {
fmt.Printf("%s %s → %v\n", route.Method, route.Path, route.HandlerNames)
}
// GET /health → [main.healthHandler]
// POST /api/users → [controllers.CreateUser]
HandlerNames 透過 runtime.FuncForPC 反射取得,供 Manifest 和偵錯使用。
HEAD 自動回應
若路由只註冊了 GET handler,HEAD 請求會自動使用 GET handler 回應(不需重複註冊):
r.GET("/api/status", statusHandler)
// HEAD /api/status → 自動使用 statusHandler(回應不含 body)
尾部斜線重導向
啟用 WithStrictSlash(true) 時,自動將 /path ↔ /path/ 重導向(HTTP 301):
r := router.New(router.WithStrictSlash(true))
r.GET("/users", listUsers)
// GET /users/ → 301 重導向到 /users
// GET /users → 正常回應
GC 優化
Router 在高併發路徑上做了兩項 GC 優化:
Params Pool
makeContextParams() 使用 hypcontext.AcquireParams() 從 pool 取得 Params slice,避免每請求 make(Params, n) 分配。路由參數在請求結束後歸還 pool。
RouteCache cacheItem Pool
LRU 快取的 cacheItem 使用 sync.Pool 管理。新增快取項目時從 pool 取得,淘汰時清空欄位後歸還,消除頻繁的 &cacheItem{} 分配。