Beego中无传统中间件概念,仅通过InsertFilter注册函数实现类似功能;需用ctx.Next()显式控制流程,且BeforeRouter与BeforeStatic隔离,路径匹配不支持正则,终止请求应使用AbortWithStatusJSON。

Beego里根本没有“中间件”这个概念,只有Filter
Beego v2.x 不提供 Use()、UseMiddleware() 或类似 Express/Koa 的中间件链抽象。所谓“中间件”,实际就是 beego.InsertFilter() 注册的 func(*context.Context) 函数。试图把其他框架的中间件代码直接搬过来会编译失败或静默失效。
迁移时第一件事是删掉所有 next()、return next() 这类调用——Beego 用 ctx.Next() 控制流程,且它必须显式调用,否则后续 Filter 和 Controller 完全不执行。
-
ctx.Next()必须出现在函数体中,且通常放在逻辑分界处(如鉴权通过后) - 没调
ctx.Next()就等于终止整个请求链,但不会自动返回响应,容易造成客户端挂起 - 不能在
ctx.Next()后写响应体(如c.Ctx.WriteString()),因为 Controller 可能已写过内容,导致http: multiple response.WriteHeader callspanic
BeforeRouter 和 BeforeStatic 是两个完全隔离的通道
想让“同一个鉴权逻辑”同时覆盖 API 和私有静态资源(如 /static/private/report.pdf),不能只注册一次。Beego 把这两类请求的生命周期彻底分开:
-
BeforeRouter:所有非静态路由请求走这里,ctx.Input.Param()可用,session 已初始化 -
BeforeStatic:仅静态文件请求触发,ctx.Input大部分字段为 nil,ctx.Input.Param()会 panic,必须手动解析ctx.Request.URL.Path - 注册
beego.InsertFilter("/api/", beego.BeforeRouter, authFilter)对/static/xxx完全无效 - 注册
beego.InsertFilter("/static/private/", beego.BeforeStatic, staticAuthFilter)才能拦住对应路径
这意味着你得写两套几乎相同的逻辑,只是参数提取方式不同。别试图复用函数指针——签名虽同,但运行时上下文能力差太多。
路径匹配规则不是正则,通配符行为很具体
Beego 的 pattern 参数支持前缀匹配和简单通配,但不支持完整正则。迁移时常见误配:
-
"/api"会匹配/apixxx和/api/v1—— 因为它是纯字符串前缀比较 -
"/api/"才安全,结尾斜杠能排除误伤 -
"/api/*"支持星号通配,等价于“以 /api/ 开头”,但*值不可直接取,要靠ctx.Input.Param(":splat")(需开启params: true选项) -
"/user/:id([0-9]+)"这种带正则的写法只在路由定义(beego.Router)中有效,在InsertFilter里会被当字面量处理,无法提取参数
如果你原来依赖 Express 的 /api/:version/users/:id 动态段做分流,Beego 里得改用 BeforeRouter + 手动 strings.Split(ctx.Request.URL.Path, "/") 或正则提取,再 switch 分支。
AbortWithStatusJSON 是终止请求的唯一可靠方式
很多迁移者卡在“拦截了但前端收不到错误体”。原因在于:ctx.Abort(401) 只中断流程,不写响应;而 ctx.Redirect() 在 BeforeStatic 阶段会 panic(无 router 上下文)。
- 必须用
ctx.AbortWithStatusJSON(401, map[string]string{"error": "token expired"}) - 它内部自动调用
WriteHeader()和json.Marshal(),无需额外操作 - 若需加自定义 header(如
X-RateLimit-Remaining),必须在AbortWithStatusJSON()调用前设置:ctx.ResponseWriter.Header().Set("X-RateLimit-Remaining", "0") - 不要在
BeforeStatic里调ctx.AbortWithStatusJSON()后还试图读ctx.Input.Session()——session 根本没初始化,会 panic
最易忽略的一点:AbortWithStatusJSON() 返回的是 JSON,Content-Type 默认为 application/json; charset=utf-8。如果前端 Expect text/plain,得手动覆盖:ctx.ResponseWriter.Header().Set("Content-Type", "text/plain; charset=utf-8"),再调 ctx.Abort(400) + 自己写 body。











