revel过滤器是需手动调用链中下一个的固定签名函数,必须用fc[0](c, fc[1:])递归传递剩余切片,全局注册于app/init.go的revel.filters,顺序决定执行时机,错序或漏调将导致卡死、崩溃或header已写错误。

Revel 的过滤器不是「拦截器」,也不是 Spring 那种 HandlerInterceptor;它是一个固定签名的函数类型 func(*revel.Controller, []revel.Filter),必须手动调用链中下一个过滤器 —— 漏掉这步,请求就卡死,控制器永远不会执行。
过滤器函数签名和链式调用必须写对
Revel 的 Filter 类型强制要求你显式控制执行流。不像 Servlet Filter 里调用 chain.doFilter() 就完事,Revel 要你从切片里取下一个、传入剩余链,自己递归触发。
- 错误写法:
fc[0](c, fc)—— 会无限循环,因为没截断切片 - 正确写法:
fc[0](c, fc[1:])—— 每次把当前过滤器剔除,传给下一个 - 如果
len(fc) == 0,说明已到链尾,此时不调用任何过滤器,直接进入业务逻辑(或返回) - 必须在调用
fc[0](c, fc[1:])前/后加业务逻辑,否则就是空过滤器
全局注册要改 revel.Filters 切片,不是加 Bean
Revel 没有自动扫描或注解注册机制。所有过滤器都靠替换 revel.Filters 全局变量生效,位置固定在 app/init.go 的 init() 函数里。
- 不能在 controller 或 action 里动态注册
- 顺序决定执行时机:比如想在
SessionFilter之前读 cookie,就得把它插在SessionFilter前面 - 删掉
ActionInvoker会导致控制器方法永不调用;删掉RouterFilter会让所有路由 404 - 修改后必须重启服务,热重载不生效
Per-action 过滤器配置依赖 FilterConfiguringFilter
想只对某个 controller 或 action 加日志、权限校验?得靠 FilterConfiguringFilter 提供的钩子,它本身是默认链一员,但只负责“改链”,不处理请求。
- 必须确保
FilterConfiguringFilter在RouterFilter之后、ActionInvoker之前 - 配置写法示例:
revel.Intercept((*App).AdminOnly, revel.BEFORE),其中AdminOnly是自定义 filter 函数 -
revel.BEFORE表示插入到目标 action 执行前,revel.AFTER表示响应写出后 - 这个机制不支持条件跳过(比如只对 POST 生效),需在 filter 函数内手动判断
c.Request.Method
常见崩溃点:panic 后没恢复、filter 返回早于 chain 调用
最典型的两个运行时失败场景,都跟控制流误操作有关:
- 在 filter 中 panic 且没包在
defer+recover里 → 整个 HTTP server 崩溃,因为PanicFilter只包裹链执行,不包裹单个 filter 内部逻辑 - 在调用
fc[0](c, fc[1:])前就写了c.RenderError(401)或c.Redirect(...)→ 请求被响应,但后续 filter 仍会执行(比如SessionFilter还会尝试写 session),可能触发 “header already written” 错误 - 异步 goroutine 里直接用
c→*revel.Controller不是线程安全的,session/flash 等字段可能被并发读写破坏
真正难的不是写一个 filter,而是理解它嵌在固定链里的位置约束 —— 比如你想改请求参数,必须在 ParamsFilter 之前;想读 session 数据,必须在 SessionFilter 之后。顺序错了,c.Params 或 c.Session 就是空的。











