Buffalo中间件必须符合buffalo.MiddlewareFunc签名,即func(next buffalo.Handler) buffalo.Handler,且需显式调用c.Next();注册顺序决定执行逻辑,层级分app.Use、Group.Use和路由.Use;读取Body需缓存重置,Header修改直接Set,Context透传需手动构造。

Buffalo 的中间件不是“加进去就行”,而是必须符合 buffalo.MiddlewareFunc 类型签名,且注册顺序直接影响执行逻辑——错一位,鉴权就失效、日志就漏记、panic 就没捕获。
中间件函数签名必须是 buffalo.MiddlewareFunc
Buffalo 不接受标准库那种 func(http.Handler) http.Handler 形式。它要求中间件函数接收一个 buffalo.Handler 并返回一个新的 buffalo.Handler,内部必须显式调用 c.Next() 才能放行请求。
- 错误写法:
func(r *http.Request) { ... }或func(w http.ResponseWriter, r *http.Request) { ... }—— 编译通不过,app.Use()直接 panic - 正确结构:
func MyMiddleware(next buffalo.Handler) buffalo.Handler { return func(c buffalo.Context) error { // 前置逻辑:比如打印路径 fmt.Println("→", c.Request().URL.Path) // 必须调用 c.Next(),否则请求卡死 err := c.Next() // 后置逻辑:比如记录耗时 fmt.Println("←", c.Response().Status) return err } } - 注意:
c.Next()是同步阻塞调用,不是 goroutine 启动;它会等下游所有中间件和 handler 执行完才返回
注册位置决定是否全局生效
中间件注册点有三个层级,行为完全不同:
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
-
app.Use(MyMiddleware):注册到整个应用,包括/public/静态资源(除非你禁用了Static中间件) -
app.Group("/api", func(g *buffalo.RouterGroup) { g.Use(MyMiddleware); ... }):仅作用于该前缀下的路由,适合 API 鉴权 -
app.GET("/health", HealthHandler).Use(MyMiddleware):只对该路由生效,极少用,调试时临时加日志可用 - 常见坑:在
app.Use()之后又调app.Use(pop.Transaction(app.DB)),结果自定义中间件里读不到c.Value("tx")—— 因为pop.Transaction在链上更靠后
中间件里读取和修改请求体要小心
Buffalo 的 c.Request().Body 和标准库一样是一次性流。如果你在中间件里调了 io.ReadAll(c.Request().Body),后续 handler 再读就是空的。
- 必须缓存并重置:
bodyBytes, _ := io.ReadAll(c.Request().Body); c.Request().Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) - 但别对大文件这么做——生产环境应限制 JSON body 大小(用
app.Options.MaxBodySize),或改用流式解析 - 想取原始 payload?优先用
c.Request().Body,而不是c.Param("xxx")或c.FormValue("xxx")—— 后两者依赖解析逻辑,可能被前面中间件干扰 - 修改请求头(如加
X-Request-ID)直接写:c.Request().Header.Set("X-Request-ID", uuid.NewString())
最易被忽略的是 context 透传:Buffalo 中间件默认不自动把 c.Request().Context() 传给下游调用(比如 http.Client.Do())。如果要做超时控制,必须手动构造新 context:ctx, cancel := context.WithTimeout(c.Request().Context(), 5*time.Second),并在调用完成后 cancel()。

















