beego真正的中间件机制是insertfilter(),而非prepare();前者支持全局路径匹配、多时机注入(如beforerouter)、统一配置与监控,后者仅为controller级钩子,易导致逻辑分散、复用困难、无法覆盖静态资源等非controller请求。

Beego 没有传统意义上的“中间件链”概念,它的请求拦截主要靠 Prepare() 和 InsertFilter() 两条路径,选错会导致逻辑分散、复用困难、无法统一管控。
Prepare() 是 Controller 级预处理,不是中间件
很多新手直接在每个 Controller 的 Prepare() 方法里写日志、鉴权或限流逻辑,这看似简单,实则埋下三个坑:
- 配置无法集中管理(比如限流阈值散落在多个 Controller 里)
- 无法对静态资源、404 路由等非 Controller 请求生效
- 测试和替换成本高,改一个逻辑要翻遍所有 Controller 文件
它本质是 MVC 中 Controller 的生命周期钩子,不是中间件。适合做当前 Controller 特有的初始化(如加载关联 model),不适合通用横切逻辑。
InsertFilter() 才是真正的全局中间件注册点
beego.InsertFilter() 是 Beego 提供的、符合中间件语义的机制,它把函数注入到 HTTP 处理链中,支持按路径匹配、执行时机(beego.BeeApp.Handlers 前/后)、优先级排序。
典型用法:
func LogMiddleware(ctx *context.Context) {
log.Printf("[INFO] %s %s", ctx.Request.Method, ctx.Request.URL.Path)
ctx.Next()
}
func init() {
beego.InsertFilter("/*", beego.BeforeRouter, LogMiddleware)
}
注意几个关键点:
-
"/*"表示匹配所有路由;也可写"/api/*"或正则"/v1/.*" -
beego.BeforeRouter表示在路由分发前执行(适合鉴权、限流);beego.AfterExec表示 Controller 执行完、渲染前(适合响应头注入、耗时统计) - 多个
InsertFilter()按注册顺序倒序执行(即后注册的先运行),类似 Express 的中间件栈
为什么不要用 RunWithMiddleWares() 封装标准 http.Handler
虽然 Beego 底层基于 net/http,也暴露了 RunWithMiddleWares() 接口,但直接用它包装第三方中间件(如 gorilla/handlers)容易出问题:
- Beego 的
context.Context对象不会自动透传给下游http.Handler,你拿不到ctx.Input、ctx.Output等 Beego 特有字段 - Session、Flash、ORM 自动注入等 Beego 运行时上下文会丢失
- 错误处理机制不兼容:Beego 的 panic 捕获、
Abort()、Redirect()在纯http.Handler中失效
除非你明确放弃 Beego 生态(比如只用它当 HTTP server 容器),否则应坚持用 InsertFilter() + Beego 原生 context.Context。
限流、CORS、JWT 验证这类通用逻辑必须走 InsertFilter
以限流为例,如果硬塞进 Prepare(),你就得在每个 API Controller 里重复 new rate.Limiter、判断、返回 429 ——而用 InsertFilter() 可以做到:
- 统一配置:从配置文件读取
limit=100&burst=200 - 动态 key:用
ctx.Request.RemoteAddr或ctx.Input.Header("X-User-ID")做限流维度 - 统一响应:调用
ctx.Abort(429, "Too Many Requests")并设Retry-After头 - 可观测:在 filter 入口打日志,天然聚合所有被限流请求
Beego 的 context.Context 是贯穿始终的载体,所有真正需要复用、可插拔、可监控的逻辑,都该基于它构建并注册到 InsertFilter(),而不是退化成 Controller 内部的私有方法。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











