

新闻资讯
技术学院Go中责任链模式核心是函数链式调用与中间件式委托,关键在于显式调用next.ServeHTTP()或next(ctx)移交控制权,而非类继承结构;常用http.Handler实现Web中间件链,或自定义ChainFunc处理业务逻辑。
Go 没有类继承和抽象方法,所以责任链不能照搬 Java 那套 Handler 接口 + setNext() 的写法。它的本质是「函数链式调用 + 中间件式委托」:每个处理单元接收一个 http.Handler 或自定义上下文,决定是否继续传递请求。
关键不在“链”的形态,而在「控制权移交」——上一环调用 next.ServeHTTP() 或 next(ctx) 才算真正把请求往下传。
这是生产环境最稳妥的做法,天然兼容 net/http 生态,中间件可复用(如 gorilla/mux、chi 都基于此)。
http.Handler 并返回新 http.Handler
next.ServeHTTP(w, r),否则链就断了func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("request: %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r) // ← 不写这行,后续中间件和最终 handler 都不会执行
})
}
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return // ← 提前返回,不调用 next,链在此终止
}
next.ServeHTTP(w, r)
})
}
// 使用:链式组合
handler := loggingMiddleware(authMiddleware(http.HandlerFunc(homeHandler)))
http.ListenAndServe(":8080", handler)
当处理的是内部业务逻辑(比如审批流、数据校验、事件分发),更适合定义一个可组合的函数链:
ChainFunc 类型为 func(context.Context) error
ctx 和 next ChainFunc,自行决定是否调用 next(ctx)
context.WithValue() 传递(但要克制)type ChainFunc func(context.Context) error
func WithValidation(next ChainFunc) ChainFunc {
return func(ctx context.Context) error {
data := ctx.Value("data").(string)
if len(data) == 0 {
return errors.New("empty data")
}
return next(ctx)
}
}
func WithPersistence(next ChainFunc) ChainFunc {
return func(ctx context.Context) error {
// save to DB...
return next(ctx)
}
}
// 组装
chain := WithValidation(WithPersistence(func(ctx context.Context) error {
fmt.Println("done")
return nil
}))
err := chain(context.WithValue(context.Background(), "data", "ok"))
责任链不是语法糖,是控制流设计,错一处就
全链失效:
defer/recover
ctx.WithTimeout(),每个环节都要用该 ctx 调用下游,否则超时失效for _, m := range mw { chain = m(chain) }),要用临时变量或索引避免引用同一地址链越长,调试越难。上线前务必用真实请求路径覆盖「正常流转」「提前中断」「panic 触发」三种情况。