beego.InsertFilter 是过滤器注册工具而非中间件本身,它将函数指针、路径和执行阶段绑定存入BeeApp.Handlers;真正调度在serveHTTP和execFilter中按阶段遍历调用。

beego.InsertFilter 是注册入口,不是中间件本身
Beego 的“中间件”本质是过滤器函数,beego.InsertFilter 只是注册工具,不是执行逻辑所在。它把函数指针、匹配路径、执行阶段三者绑定,存进 BeeApp.Handlers 的多层 map 结构里。源码中真正调度这些过滤器的位置在 server/web/router.go 的 serveHTTP 和 execFilter 方法中——请求进来后,框架按阶段遍历匹配的过滤器列表并逐个调用。
常见误读是以为 InsertFilter 会立即生效或自动包装逻辑,其实它只是往全局变量里塞了个函数地址。所以:
-
beego.InsertFilter必须在beego.Run()前调用,否则BeeApp尚未启动,Handlers 还没开始监听 - 注册时传入的路径(如
"/api/")会被转为前缀匹配逻辑,不支持通配符或正则 - 同一阶段注册多个过滤器,顺序严格按
InsertFilter调用先后,没有优先级字段
BeforeStatic 阶段的 ctx 是“残缺”的,不能当 Controller 用
静态资源请求(如 /static/private/file.pdf)绕过整个路由系统,直接由 http.ServeFile 处理。因此 beego.BeforeStatic 是唯一能拦截它的过滤点,但此时 ctx.Input.Param()、ctx.Controller、ctx.Data 全为 nil —— 因为 controller 实例根本没创建。
你只能安全访问:ctx.Request.URL.Path、ctx.Request.Header、ctx.ResponseWriter。例如做权限校验时:
- 别写
ctx.Input.Session.Get("user_id")—— Session 初始化发生在BeforeRouter后,BeforeStatic 里尚未触发 - 要提取路径参数(如
/static/users/:id/),得自己用strings.Split或正则从ctx.Request.URL.Path切,ctx.Input.Param(":id")一定返回空 - 终止请求必须用
ctx.Abort(403, "Forbidden"),不能只return,否则文件仍会吐出
ctx.Next() 不是回调,是同步控制流跳转
ctx.Next() 看似像 Express 的 next(),实则是 Beego 自己实现的协程内控制流指令。它不启动新 goroutine,也不注册回调;而是直接跳到当前阶段的下一个过滤器函数,或最终落到 controller 上。如果漏掉它,链路就断了——后续所有过滤器和 controller 都不会执行。
典型错误包括:
- 在条件判断后忘记调用
ctx.Next(),比如权限检查通过后直接return - 用
defer ctx.Next()—— defer 是函数退出时才执行,而ctx.Next()必须在当前函数逻辑中显式调用 - 在
ctx.Abort()后还调用ctx.Next()—— Abort 已设置响应状态,Next 会 panic
FilterFunc 签名固定,不能改参数或返回值
Beego 过滤器函数签名被硬编码在 server/web/filter.go 中:func(*context.Context)。你无法加第二个参数(如 error),也不能返回值。所有状态传递必须靠修改 ctx 对象本身(如设 ctx.Input.SetData)或外部变量(如全局 map 缓存 session ID)。
这意味着:
- 想在多个过滤器间透传数据,不能靠返回值,得用
ctx.Input.Data["key"] = value - 错误处理不能靠 return error,得用
ctx.Abort(500, "xxx")或手动写响应体 +ctx.ResponseWriter.WriteHeader() - 不要试图给过滤器加 context.WithTimeout ——
ctx是 Beego 的*context.Context,不是 Go 标准库的context.Context,两者不兼容
最易被忽略的是:BeforeStatic 和 BeforeRouter 的 ctx 生命周期完全独立,前者拿不到后者初始化的任何上下文字段。如果你同时需要 API 权限和静态资源权限,就得写两套逻辑,分别注册到不同阶段——没有“统一中间件”这回事。











