beego的过滤器是嵌入请求生命周期的函数钩子,非链式中间件;必须正确填写insertfilter四参数:pattern支持通配符与正则,position须选五个预定义常量之一,filter签名必须为func(*context.context),skip设true表示有输出时跳过同位置后续过滤器。

Beego 的“中间件”就是 Filter,不是独立组件,而是嵌入请求生命周期的函数钩子;它不支持链式调用(如 Express 或 Gin 那种 next() 显式传递),而是靠注册顺序 + 位置控制执行时机,误用位置或忽略初始化顺序会导致 session 拿不到、静态资源拦不住、跳转失效等静默失败。
beego.InsertFilter 的四个参数到底怎么填
beego.InsertFilter 看似简单,但第二、三、四参数稍有偏差就会让过滤器不触发或行为异常:
-
pattern:支持通配符*和正则路径(如/user/:id([0-9]+)),但注意——/*匹配所有路由,*(无斜杠)只匹配根路径,别写错 -
position:必须从beego.BeforeStatic、beego.BeforeRouter、beego.BeforeExec、beego.AfterExec、beego.FinishRouter中选,不能传数字或自定义常量 -
filter:函数签名必须是func(*context.Context),多一个参数或少一个星号都会编译报错 -
skip(第四个参数):默认为false,设为true表示“一旦有输出(如ctx.Redirect、ctx.Abort、ctx.Output.JSON)就跳过后续同位置过滤器”,不是跳过所有过滤器
静态资源(/static/)为什么拦不住?
因为 Beego 对静态文件请求做了短路处理:只要命中 beego.StaticDir 配置的路径(如 /static/),就直接由内置静态处理器响应,完全绕过路由匹配和 BeforeRouter / BeforeExec 阶段。
所以这类需求——比如限制 /static/users/123/private/report.pdf 只能被对应用户访问——必须用 beego.BeforeStatic:
- 注册时 pattern 要精确,例如
"/static/users/:id([0-9]+)/private/*" - 在 filter 函数里用
regexp提取 URL 中的id,再比对 session 中的登录用户 ID - 不能依赖
ctx.Input.Session("uid")—— session 在BeforeStatic时尚未初始化,得手动从 cookie 解析或走beego.GlobalSessions.SessionStart
session 在哪个位置才能安全读取
Session 初始化发生在 BeforeRouter 之后、BeforeExec 之前。这意味着:
-
beego.BeforeStatic:session 未初始化,ctx.Input.Session返回 nil -
beego.BeforeRouter:session 仍未初始化(文档明确警告:“使用 session 的 Filter 必须在BeforeStatic之后才能获取”——这句话其实是错的,正确是“必须在BeforeRouter之后”) -
beego.BeforeExec及以后:session 已可用,可安全调用ctx.Input.Session("uid")
常见错误:在 BeforeRouter 里做登录校验并调 ctx.Redirect,结果重定向后 session 为空,又跳回登录页,形成死循环。
如何模拟 RESTful 方法(如 PUT/DELETE)
前端用 _method=DELETE 伪造请求时,Beego 默认只认原始 HTTP 方法,会返回 405。解决方式是在 BeforeRouter 插入一个预处理 filter:
- 读取
ctx.Input.Query("_method") - 确认该方法在允许列表(
GET、POST、PUT、DELETE等)内 - 若当前是 POST 且
_method有效,则覆写ctx.Request.Method = "DELETE" - 注意:覆写后需确保后续路由规则支持该方法,比如
beego.Router("/api/user/:id", &c.UserController{}, "delete:Delete")
这个 filter 必须放在 BeforeRouter,否则路由匹配阶段已按原始 POST 处理,覆写就晚了。
最易被忽略的一点:Beego 的 filter 不是“中间件链”,没有隐式 next;ctx.Next() 是可选调用,仅用于手动触发后续同位置 filter(极少用),绝大多数场景下你只需专注当前 filter 的逻辑分支与提前终止(ctx.Abort / ctx.Redirect),别试图模仿其他框架的流程控制习惯。











