
通过自定义 Handler 包装器(middleware),可在不修改每个处理器逻辑的前提下,自动为所有响应统一设置 Server 等公共 Header,避免重复调用 rw.Header().Set()。
通过自定义 handler 包装器(middleware),可在不修改每个处理器逻辑的前提下,自动为所有响应统一设置 `server` 等公共 header,避免重复调用 `rw.header().set()`。
在 Go 的 net/http 中,http.Handler 是一个接口,而 http.HandlerFunc 是其函数式实现。利用这一特性,我们可以构建轻量、可复用的中间件——即一个接收 http.Handler 并返回新 http.Handler 的包装函数。
以下是一个标准的 Header 注入中间件示例:
const SERVER_NAME = "MyAwesomeAPI/1.0"
func withServerHeader(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Server", SERVER_NAME)
h.ServeHTTP(w, r)
})
}
该中间件可灵活应用于多种场景:
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
-
包装单个路由处理器:
http.Handle("/signup", withServerHeader(http.HandlerFunc(httpSignUp))) http.Handle("/login", withServerHeader(http.HandlerFunc(httpLogin))) -
包装整个服务根处理器(推荐):
若使用 http.ServeMux 作为根路由,只需包装一次即可全局生效:mux := http.NewServeMux() mux.HandleFunc("/signup", httpSignUp) mux.HandleFunc("/login", httpLogin) mux.HandleFunc("/health", httpHealth) log.Fatal(http.ListenAndServe(":8080", withServerHeader(mux)))
⚠️ 注意事项:
- Header 必须在 h.ServeHTTP() 之前 设置,否则响应已写入(如已调用 w.WriteHeader() 或写入 body),再修改 Header 将被忽略;
- 若后续中间件或处理器自身也设置了 Server 头,将发生覆盖(后设者生效),建议确保 Header 设置顺序可控;
- 此模式可轻松扩展为添加多个通用 Header(如 X-Content-Type-Options, X-Frame-Options),只需在包装函数中追加 w.Header().Set() 调用即可。
这种基于组合的中间件设计符合 Go 的简洁哲学:无框架依赖、类型安全、零运行时开销,是构建可维护 HTTP 服务的基础实践。










