go语言无@decorator语法,所有装饰器均为手动函数包装或接口组合;http中间件因强制func(http.handler) http.handler签名而最稳定,需用http.handlerfunc转换、显式调用next.servehttp、注意执行顺序与资源清理。

Go 语言没有 @decorator 语法,所有“装饰器”都是手动函数包装或接口组合,写错签名、漏调 next.ServeHTTP、忘记 defer cancel(),它就直接失效。
func(http.Handler) http.Handler 是最稳的起点
HTTP 中间件是 Go 里装饰器模式最自然、最不易翻车的落地场景,因为标准库强制了统一签名:func(http.ResponseWriter, *http.Request),所有中间件都按这个来,天然可链。
- 不转
http.HandlerFunc,闭包就不是http.Handler,http.Handle直接拒绝注册 - 中间件里必须显式调用
next.ServeHTTP(w, r),漏掉等于请求静默丢弃 - 顺序决定执行流:写成
LoggingMiddleware(AuthMiddleware(h)),实际是 Logging 先进、最后出,Auth 在中间 - 错误示例:
return func(w http.ResponseWriter, r *http.Request) { ... }—— 缺少http.HandlerFunc(...)包裹,类型不匹配
withTimeout 要 defer cancel(),且原函数得响应 ctx.Done()
超时装饰器不是套一层 context.WithTimeout 就完事;不 defer cancel() 会泄漏 goroutine,原函数不检查 ctx.Done() 则超时后仍继续执行。
-
withTimeout必须返回func(context.Context) error类型,才能和重试、日志等其他装饰器叠加 - 多个装饰器嵌套时顺序敏感:
withTimeout(withRetry(f))表示整体超时,每次重试共享同一 deadline;反过来则每次重试都带独立 timeout - 别在闭包里捕获
panic后只打日志不re-panic,否则上层收不到错误,HTTP handler 可能静默返回 200 - 常见错误:把
ctx存在结构体字段里长期持有,导致 context 生命周期失控
Chain 辅助函数摊平嵌套,避免括号套娃
写成 WithRetry(3)(WithTimeout(5*time.Second)(WithLogging(handler))) 不仅难读,还容易手抖少个括号,编译失败定位困难。
- 用
Chain把装饰器列表“摊平”:Chain(WithLogging, WithTimeout(5*time.Second), WithRetry(3))(handler) -
Chain内部就是从右往左依次调用,等价于手动嵌套,但更清晰、更易维护 - 结构体嵌入比闭包更适合有状态逻辑(如带配置的限流器),闭包适合轻量无状态操作(如 CORS 头)
- 结构体方式可单独单元测试,不用启动 HTTP 服务;闭包方式一旦带了外部变量捕获,测试边界容易模糊
真正容易被忽略的不是怎么写,而是谁负责清理资源、谁响应取消、谁记录错误链——这些细节不显眼,但一出问题就是 goroutine 泄漏、请求卡死、错误丢失。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











