Revel拦截器必须用revel.BEFORE等标识注册,函数签名须返回revel.Result,且注册须在init()中、revel.Harness.Init()之前;BEFORE阶段返回非nil结果会终止请求链,顺序错误或热重载遗漏将导致逻辑失效。

Revel 拦截器必须用 revel.BEFORE 等生命周期标识注册,且函数签名必须返回 revel.Result;漏写返回值、错用 return nil 以外的空值、或在 BEFORE 阶段意外返回非 nil 结果,都会导致请求静默中断或路由失效。
拦截器函数签名和返回值不能出错
Revel 不接受任意签名的“中间件函数”。合法拦截器只接受两种形式:
- 函数拦截器:
func(c *revel.Controller) revel.Result—— 必须接收指针类型*revel.Controller,且必须显式返回revel.Result(如c.Render()、c.Redirect()或nil) - 方法拦截器:
func(c AppController) revel.Result或func(c *AppController) revel.Result—— 接收控制器实例或指针,同样必须返回revel.Result
常见错误包括:
- 写成
func(c *revel.Controller)(无返回值)→ 编译失败 - 写成
func(c *revel.Controller) error→ 类型不匹配,注册后不生效 - 本该
return nil却写了return(语法错误)或return false(类型错误)
注册位置必须在 init() 中且早于 revel.Harness.Init()
拦截器必须在 Revel 框架初始化前完成注册,否则会被忽略。典型注册位置是 app/init.go 的 init() 函数内,且需确保在 revel.Harness.Init() 调用之前执行:
func init() {
// ✅ 正确:在 Harness.Init 前注册
revel.InterceptMethod(controllers.SetVersion, revel.BEFORE)
<pre class="brush:php;toolbar:false;">// ❌ 错误:放在这里会导致拦截器未被加载
// revel.Harness.Init()
revel.InterceptFunc(checkAuth, revel.BEFORE)
revel.Harness.Init() // 这行必须在所有 Intercept* 之后}
如果注册语句写在 revel.Harness.Init() 之后,拦截器完全不会被框架识别——没有报错,也没有日志,请求就“跳过”了你写的逻辑。
BEFORE 阶段返回非 nil 会直接终止整个请求链
BEFORE 拦截器一旦返回非 nil 的 revel.Result,后续所有拦截器和目标 action 都不会执行,且该 Result 就是最终响应。这既是控制权,也是高危点:
- 登录检查中
return c.Redirect(App.Login)是合理中断 - 但调试时随手写
return c.RenderError("debug")却忘了删,会导致所有请求返回 500 - 更隐蔽的是:某些自定义
Result实现未正确设置状态码或 Content-Type,浏览器收到空响应或乱码
建议在开发期对所有 BEFORE 拦截器加日志:
func checkAuth(c *revel.Controller) revel.Result {
revel.INFO.Printf("checkAuth: %s %s", c.Request.Method, c.Request.URL.Path)
if !isAuthenticated(c) {
c.Flash.Error("Not logged in")
return c.Redirect(App.Login)
}
return nil // ✅ 显式返回 nil 表示放行
}拦截器顺序影响逻辑执行,尤其是依赖关系
Revel 按 Intercept* 调用顺序执行拦截器。例如 session 初始化必须在依赖 session 的权限检查之前:
- ✅ 正确顺序:
revel.InterceptFunc(SessionFilter, revel.BEFORE)→revel.InterceptFunc(checkRole, revel.BEFORE) - ❌ 错误顺序:把
checkRole放前面,c.Session().Get("user_id")会返回nil,因为 session 还没被SessionFilter加载
Revel 默认过滤器链(如 SessionFilter、FlashFilter)已内置顺序,但自定义拦截器要手动排好——没有依赖图校验,全靠开发者理清数据流。
最易被忽略的是:拦截器本身不参与热重载。改完 init.go 里的注册代码后,必须手动重启 revel run,否则新注册的拦截器永远不会生效。


















