beego 的 filter 是基于路由匹配阶段触发的函数钩子,非传统中间件,需显式调用 ctx.next() 才继续流程;它支持五种执行位置,用于权限校验、跨域等,但不自动传递控制权,漏调 next() 会导致静默中断。

Beego 中的 Filter 是什么,和中间件有什么区别
Beego 的 Filter 不是传统意义上的中间件(比如 Gin 的 Use 或 Express 的 app.use),而是基于路由匹配前/后触发的函数钩子,注册在 beego.Router 或全局 beego.InsertFilter 上。它不自动传递控制权,必须显式调用 cont.Continue() 才会继续执行后续逻辑;漏掉这句就会静默中断请求。
常见错误现象:
- 请求没报错但页面空白或返回 404
- 日志里看不到 controller 的执行日志
-
InsertFilter注册了却完全没触发
使用场景包括权限校验、跨域头注入、请求体预处理(如解密)、灰度路由分流等。注意:Beego 1.x 和 2.x 的 filter 类型签名不同,2.x 使用 func(<em>context.Context)</em>,1.x 是 func(context.Context, *context.ControllerRegister) —— 混用会导致编译失败或 panic。
如何注册全局请求过滤器(如鉴权)
全局 filter 适合所有路由都需执行的逻辑,比如 JWT 校验、IP 白名单。用 beego.InsertFilter 注册,第一个参数是匹配路径(支持通配符),第二个是 filter 类型(beego.BeeApp.FilterTypeBeforeRouter 最常用),第三个是函数。
beego.InsertFilter("/*", beego.BeeApp.FilterTypeBeforeRouter, func(ctx *context.Context) {
auth := ctx.Input.Header("Authorization")
if !isValidToken(auth) {
ctx.Abort(401, "Unauthorized")
return
}
// 必须显式放行,否则请求终止
ctx.Next()
})
关键点:
-
"/*"匹配所有路径,但不匹配静态文件(如/static/xxx.js,除非你额外配置) -
ctx.Next()等价于cont.Continue(),Beego 2.x 推荐用前者 -
ctx.Abort()会立即终止流程并返回响应,后续 filter 和 controller 都不会执行 - 如果需要读取 request body,得先调用
ctx.Input.RequestBody,否则后续 controller 可能读不到
如何为特定路由添加前置过滤(如 /admin/* 要求管理员权限)
比全局 filter 更细粒度的控制,推荐用 beego.Router 的 FilterParam 参数,或在 controller 的 Prepare() 方法里做判断。
beego.Router("/admin/users", &controllers.AdminController{}, "get:ListUsers")
beego.InsertFilter("/admin/*", beego.BeeApp.FilterTypeBeforeRouter, adminAuthFilter)
adminAuthFilter 示例:
func adminAuthFilter(ctx *context.Context) {
userRole := ctx.Input.Session("role")
if userRole != "admin" {
ctx.Abort(403, "Forbidden")
return
}
ctx.Next()
}
注意:
- 路径匹配是前缀匹配,
/admin/*会命中/admin/users/123,但不会命中/admin(末尾无斜杠) - Session 默认基于 cookie + memory,生产环境务必改用 redis 存储,否则多实例下 session 失效
-
ctx.Input.Session在未初始化 session 时会 panic,应先用ctx.Input.IsAjax()或ctx.Input.CruSession判断
Filter 常见陷阱和性能影响
Filter 执行在路由解析之后、controller 初始化之前,所以不能修改路由参数(如 :id),也不能访问 this.Data(controller 实例还没创建)。想改参数只能靠 ctx.Input.SetData(),再在 controller 里手动取。
容易踩的坑:
- 在 filter 里调用
ctx.Output.JSON()后忘记return,导致后续仍执行 controller,产生重复响应 - 多个 filter 嵌套时,错误地在某个 filter 里
ctx.Abort()但没写明状态码,返回 200 空内容,前端难以排查 - 对上传文件接口加 filter 时,提前读了
RequestBody,导致 controller 的this.GetFiles()失败
性能方面:每个 filter 都是函数调用开销,高频接口(如心跳、埋点)上避免做 DB 查询或远程调用。必要时用 sync.Once 缓存校验结果,或把耗时操作移到异步 goroutine(但注意 context 超时和取消)。
Beego 的 filter 机制轻量但隐含约束多,最常被忽略的是「必须显式放行」和「session 初始化时机」——这两点一旦出错,问题现象模糊,日志又不报错,调试起来特别花时间。











