Go HTTP中间件是接收并返回http.Handler的包装函数,通过闭包在next.ServeHTTP前后插入逻辑,如日志、鉴权;链式调用顺序决定执行流,外层中间件先入后出;不可用普通函数替代,须解耦复用。
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.HandlerF
unc(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 没有内置中间件栈,所谓“链式”靠的是手动嵌套调用,顺序直接影响执行流。越靠外的中间件越先执行(进入时),也越晚执行(退出时)。
loggingMiddleware(authMiddleware(mainHandler)):请求进来先过 loggingMiddleware,再进 authMiddleware,最后到 mainHandler;响应返回时顺序相反w.WriteHeader 或写了响应体,后续中间件的 next.ServeHTTP 就不能再写响应(会 panic:“http: multiple response.WriteHeader calls”)常见错误是写一个普通函数,比如 func auth(r *http.Request) bool,然后在每个 handler 里手动调用——这不算中间件,只是重复逻辑。
真正中间件的价值在于解耦和复用:
http.ServeMux 本身不支持中间件注册,所以必须靠包装 Handler 实现,没有捷径复杂点在于:一旦中间件开始操作 ResponseWriter(比如封装成 responseWriterWrapper 拦截状态码),就要小心接口实现是否完整——漏掉 Flush()、Hijack() 等方法可能导致长连接或 WebSocket 异常。