middleware.md - maoxiaoyue/hypgo GitHub Wiki

Middleware Package (pkg/middleware)

middleware 套件提供了一系列針對 HypGo context.Context 量身打造的即插即用(Plug-and-play)中介軟體。透過內置的中間件鏈與群組管理功能,你可以非常輕鬆地將跨域請求、日誌記錄、限流機制以及快取等功能加諸於路由之上。

內建中間件列表

  1. Logger: 高效能的請求日誌記錄,支援記錄耗時與回應大小,甚至可排除特定路徑。
  2. Recovery: 自動攔截 Panic 並避免伺服器崩潰,可自定義 Panic 處理邏輯與 HTTP 狀態回應。
  3. CORS: 跨來源資源共用 (Cross-Origin Resource Sharing) 處理,支援各種細部配置與 Preflight 請求快取。
  4. Security: 提供 HTTP 安全標頭設定(HSTS, X-Frame-Options, CSP),所有 header 值在初始化時預計算,零 GC 壓力。
  5. RateLimiter: 提供簡易基於 Token Bucket 的基礎限流機制,可依據 IP 或是自定義規則設限。
  6. Timeout: 提供 HTTP 請求處理的最大時間限制,超過強制中斷並回應超時訊息。
  7. Cache: 將經常存取的 API 快取於記憶體中,提供自定義 TTL、Key 產生演算法與驗證邏輯。

核心設計理念

HypGo 採用 ChainGroup 模式進行中間件管理,你可以把一個或多個中間件像樂高一樣組合起來,然後透過 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 壓力