beego的filter是绑定请求生命周期的全局函数,必须用insertfilter注册,不支持per-route绑定;执行需显式调用ctx.next(),且session等组件须提前初始化。

Beego 的中间件(即 Filter)不是可插拔的独立模块,而是绑定在请求生命周期特定位置的函数,注册后全局生效,不支持 per-route 绑定或条件启用——这点和 Gin 的 Use 或 Fiber 的 Use/Get 行为有本质区别。
Beego 中间件必须用 InsertFilter 注册,不能靠路由链式调用
很多人尝试在 router.go 里写类似 beego.Router("/api", &c.ApiController{}).Middleware(auth) 的代码,会直接报错:Beego 路由对象不提供 Middleware 方法。所有过滤器必须通过 server/web.InsertFilter 显式注册,并指定执行阶段。
-
BeforeRouter:路由匹配前执行,适合做全局鉴权、IP 黑名单拦截 -
BeforeExec:控制器方法执行前,但已完成路由匹配,适合做参数预处理、权限细化(如检查用户对某资源的读写权) -
AfterExec:控制器已返回,但响应尚未写出,可修改c.Ctx.ResponseWriter或设置 Header -
FinishRouter:无论 panic 还是正常结束都会触发,适合日志收尾、指标上报
注意:BeforeStatic 只对非静态路由路径生效;若你启用了 beego.BConfig.WebConfig.StaticDir,静态文件请求默认绕过大部分 Filter,除非显式配置 beego.InsertFilter("/*", beego.BeforeStatic, ...)。
ctx.Next() 是关键,漏掉会导致后续逻辑不执行
Beego 的 Filter 执行模型是“洋葱式”,但不像 Express 那样自动流转。每个 Filter 必须显式调用 ctx.Next(),否则请求流程会在该 Filter 处中断,控制器不会被执行,也不会进入 AfterExec 阶段。
- 常见错误:在鉴权 Filter 中判断失败后只写
c.Abort(401),却忘记 return,导致后续仍执行ctx.Next() - 正确写法:判断失败后应
c.Abort(401)+return,避免继续流转 -
ctx.Next()不是异步调用,它同步执行下一个 Filter 或 Controller,所以不能在里面做阻塞 I/O(如未加 context timeout 的 HTTP 请求)
示例片段:
func AuthFilter(ctx *context.Context) {
token := ctx.Input.Header("Authorization")
if token == "" {
ctx.Abort(401)
return // 必须 return!
}
// 验证逻辑...
ctx.Next() // 继续往下走
}
与 Beego 内置组件(如 Session、ORM)共用时的初始化顺序陷阱
Session 和 ORM 初始化必须早于 Filter 注册,否则在 BeforeExec 里调用 c.StartSession() 或 orm.NewOrm() 可能 panic 或返回空实例。
- Session:需在
main.go的beego.Run()前完成配置,例如beego.BConfig.WebConfig.Session.SessionOn = true - ORM:需在
models/init.go中完成orm.RegisterDriver和orm.RegisterModel,并在main.go中调用orm.RunSyncdb(开发期)或确保orm.NewOrm()被首次调用前已注册完毕 - Filter 中若依赖 Session 数据,建议在
BeforeExec阶段取,因为BeforeRouter阶段 Session 尚未初始化(Beego 默认延迟初始化)
如果你在 Filter 里看到 nil pointer dereference 报错,大概率是访问了未初始化的 c.Input.Session 或 c.Input.CruTime 等字段。
跨域(CORS)、限流、日志等常用功能不要重复造轮子
Beego 官方虽未内置 CORS 中间件,但社区已有稳定实现,比如 beego-cors 包,其核心就是注册一个 BeforeExec Filter 设置 Header;而限流建议用 golang.org/x/time/rate + IP/Token 提取逻辑封装,别硬套第三方 middleware 包(多数为 Gin/Fiber 设计)。
- CORS 示例只需几行:
ctx.Output.Header("Access-Control-Allow-Origin", "*")+ 其他必要头 - 日志建议统一用
beego.Info/beego.Error,而非log.Printf,否则会丢失 Beego 日志级别和格式控制 - 性能敏感场景(如高频 API),避免在
BeforeRouter做数据库查询;把耗时操作尽量往后挪到BeforeExec或 Controller 内
真正容易被忽略的是:Filter 函数本身不能带闭包捕获外部变量(如数据库连接池),必须通过全局变量或依赖注入传入——Beego 不提供 Filter 构造器或 DI 支持,所有状态都要自己管理。











