17370845950

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

什么是Go HTTP中间件,它长什么样

Go 的 HTTP 中间件本质就是 http.Handlerhttp.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”)
  • 推荐把「可能终止流程」的中间件(如鉴权、限流)放在外层,把「只读操作」的(如日志、CORS)放内层

为什么不能直接用普通函数当中间件

常见错误是写一个普通函数,比如 func auth(r *http.Request) bool,然后在每个 handler 里手动调用——这不算中间件,只是重复逻辑。

真正中间件的价值在于解耦和复用:

  • 它不侵入业务 handler,不增加 handler 的参数或返回值
  • 可以统一配置(比如所有路由都加日志,但 /health 不加),只需调整链式调用位置
  • 标准库的 http.ServeMux 本身不支持中间件注册,所以必须靠包装 Handler 实现,没有捷径

复杂点在于:一旦中间件开始操作 ResponseWriter(比如封装成 responseWriterWrapper 拦截状态码),就要小心接口实现是否完整——漏掉 Flush()Hijack() 等方法可能导致长连接或 WebSocket 异常。