middleware.md - maoxiaoyue/hypgo GitHub Wiki
Middleware Package (pkg/middleware)
middleware 套件提供了一系列針對 HypGo context.Context 量身打造的即插即用(Plug-and-play)中介軟體。透過內置的中間件鏈與群組管理功能,你可以非常輕鬆地將跨域請求、日誌記錄、限流機制以及快取等功能加諸於路由之上。
內建中間件列表
- Logger: 高效能的請求日誌記錄,支援記錄耗時與回應大小,甚至可排除特定路徑。
- Recovery: 自動攔截 Panic 並避免伺服器崩潰,可自定義 Panic 處理邏輯與 HTTP 狀態回應。
- CORS: 跨來源資源共用 (Cross-Origin Resource Sharing) 處理,支援各種細部配置與 Preflight 請求快取。
- Security: 提供 HTTP 安全標頭設定(HSTS, X-Frame-Options, CSP),所有 header 值在初始化時預計算,零 GC 壓力。
- RateLimiter: 提供簡易基於 Token Bucket 的基礎限流機制,可依據 IP 或是自定義規則設限。
- Timeout: 提供 HTTP 請求處理的最大時間限制,超過強制中斷並回應超時訊息。
- Cache: 將經常存取的 API 快取於記憶體中,提供自定義 TTL、Key 產生演算法與驗證邏輯。
核心設計理念
HypGo 採用 Chain 與 Group 模式進行中間件管理,你可以把一個或多個中間件像樂高一樣組合起來,然後透過 Then 附加到最終的 Handler 上面。
簡單載入單個內建中間件
以 Logger 為例,使用預設配置掛載:
package main
import (
"github.com/maoxiaoyue/hypgo/pkg/middleware"
"github.com/maoxiaoyue/hypgo/pkg/router"
"github.com/maoxiaoyue/hypgo/pkg/context"
)
func main() {
r := router.New()
// 使用預設設定加上 Logger 中介軟體
r.Use(middleware.Logger(middleware.LoggerConfig{}))
r.GET("/ping", func(c *context.Context) {
c.String(200, "pong")
})
}
多個中間件串聯 (Chain)
你也可以透過 middleware.Chain 將中間件先綑綁成一個群組再服用:
// 建立一個基礎的安全呼叫鏈
apiChain := middleware.NewChain(
middleware.Recovery(middleware.RecoveryConfig{}), // 防止崩潰
middleware.Logger(middleware.LoggerConfig{}), // 日誌記錄
middleware.CORS(middleware.CORSConfig{
AllowOrigins: []string{"https://example.com"},
}),
)
// 結合自訂函數
r.GET("/api/data", apiChain.Then(func(c *context.Context) {
c.JSON(200, map[string]string{"msg": "secure data"})
}))
建立前綴中間件群組 (Group)
如果你的特定路由前綴(如 /admin)需要特定的中間件邏輯:
// 宣告一個以 `/admin` 開頭的群組,並附加 RateLimiter
adminGroup := middleware.NewGroup("/admin", middleware.RateLimiter(middleware.RateLimiterConfig{
Rate: 10, // 每秒 10 個請求
Burst: 20, // 瞬間最大容量 20
}))
// 為特定的路由套用該群組的中介軟體
r.GET("/admin/dashboard", adminGroup.Handle(func(c *context.Context) {
c.String(200, "Admin View")
}))
自製中間件
你隨時可以依照 func(*hypcontext.Context) 這個型別,寫出自己的通用中間件。只要確保在邏輯的最後執行 c.Next() 以順利推進執行鏈:
func MyCustomMiddleware() hypcontext.HandlerFunc {
return func(c *hypcontext.Context) {
// 1. 在處理請求前執行的邏輯
c.Set("my_key", "my_value")
// 2. 將控制權交給下一個中介軟體或是 Handler
c.Next()
// 3. 在處理結束準備回應前執行的邏輯
status := c.Writer.Status()
log.Printf("Response Status: %d", status)
}
}
新增中間件
BodyLimit — 請求大小限制
防止大 payload DoS 攻擊:
r.Use(middleware.BodyLimit(middleware.BodyLimitConfig{
MaxBytes: 5 << 20, // 5MB
ErrorMsg: "Payload too large",
}))
MethodOverride — HTTP 方法覆蓋
支援不支援 PUT/DELETE 的客戶端(如 HTML 表單):
r.Use(middleware.MethodOverride())
// POST /users?_method=DELETE → 變成 DELETE /users
// POST /users (X-HTTP-Method-Override: PUT) → 變成 PUT /users
安全修復紀錄
| 問題 | 修復 |
|---|---|
| RateLimiter sync.Map 記憶體洩漏 | 加入定期清理(每 5 分鐘清除 10 分鐘未見的 key) |
| JWT middleware 驗證為空殼 | 改為要求 Validator 函式,未提供一律拒絕(安全預設) |
| Brotli 壓縮發假 header | 移除假 Content-Encoding: br,僅保留 gzip |
| CircuitBreaker 競態條件 | 加入 sync.Mutex 保護狀態讀寫 |
| CSRF/RequestID 用不安全的 fastrand | 改用 crypto/rand |
GC 優化:Security Header 預計算
Security 中間件在初始化時將所有 header 值(XSS、nosniff、HSTS、CSP)預計算為不可變字串,閉包捕獲。請求處理時直接設定字串,不做 fmt.Sprintf 或字串拼接:
// 初始化時一次性計算
sec := middleware.Security(middleware.SecurityConfig{
HSTSMaxAge: 31536000,
HSTSIncludeSubdomains: true,
})
// → 預計算 hstsValue = "max-age=31536000; includeSubDomains"
// → 每請求只執行 c.Header("Strict-Transport-Security", hstsValue)
// → 零分配、零 GC 壓力