Go HTTP中间件是接收并返回http.Handler的包装函数,通过闭包在next.ServeHTTP前后插入逻辑,如日志、鉴权;链式调用顺序决定执行流,外层中间件先入后出;不可用普通函数替代,须解耦复用。

什么是Go HTTP中间件,它长什么样
Go 的 HTTP 中间件本质就是 http.Handler 或 http.HandlerFunc 的包装函数,接收一个 http.Handler 并返回一个新的 http.Handler。它不依赖任何框架,纯标准库就能写。
关键点在于:中间件必须在调用 next.ServeHTTP(w, r) 前后插入逻辑,否则就不是“中间”了——比如记录日志、修改请求头、提前拦截非法请求等。
用闭包实现日志中间件(最常用模式)
这是最典型、最易理解的写法:用函数返回一个 http.Handler,内部捕获 next 处理器,并在前后加逻辑。
- 闭包能保存
next和自定义参数(如服务名、开关标志) - 避免全局变量污染,每个中间件实例彼此隔离
- 注意不要在闭包里直接调用
next.ServeHTTP,必须在返回的 handler 内部调用
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("→ %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r) // 执行下游处理器
log.Printf("← %s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
链式中间件怎么拼起来才不乱
Go 没有内置中间件栈,所谓“链式”靠的是手动嵌套调用,顺序直接影响执行流。越靠外的中间件越先执行(进入时),也越晚执行(退出时)。
立即学习“go语言免费学习笔记(深入)”;
-
loggingMiddleware(authMiddleware(mainHandler)):请求进来先过loggingMiddleware,再进authMiddleware,最后到mainHandler;响应返回时顺序相反 - 如果中间件内部调用了
w.WriteHeader或写了响应体,后续中间件的next.ServeHTTP就不能再写响应(会 panic:“http: multiple response.WriteHeader calls”) - 推荐把「可能终止流程」的中间件(如鉴权、限流)放在外层,把「只读操作」的(如日志、CORS)放内层
为什么不能直接用普通函数当中间件
常见错误是写一个普通函数,比如 func auth(r *http.Request) bool,然后在每个 handler 里手动调用——这不算中间件,只是重复逻辑。
真正中间件的价值在于解耦和复用:
- 它不侵入业务 handler,不增加 handler 的参数或返回值
- 可以统一配置(比如所有路由都加日志,但 /health 不加),只需调整链式调用位置
- 标准库的
http.ServeMux本身不支持中间件注册,所以必须靠包装Handler实现,没有捷径
复杂点在于:一旦中间件开始操作 ResponseWriter(比如封装成 responseWriterWrapper 拦截状态码),就要小心接口实现是否完整——漏掉 Flush()、Hijack() 等方法可能导致长连接或 WebSocket 异常。










