Revel框架404页面不生效,因其默认不拦截未注册路由,仅对Abort(404)或控制器内panic触发App.Error;需配置Nginx转发所有非静态路径至Revel、禁用error_page劫持,并在init.go注册InterceptFunc调用RenderError渲染views/App/404.html模板。

Revel框架的404页面为什么总不生效?
因为Revel默认不拦截「未注册路由」——它只对已匹配到控制器但执行失败(如panic、abort)或显式返回Abort(404)的请求触发App.Error;而直接访问/nonexistent这类路径,若没对应路由定义,Revel会直接返回空响应(状态码200)或由反向代理(Nginx/Apache)提前返回404。
确认是否真进了Revel:用curl -I http://localhost:9000/nonexistent看响应头。如果状态码是200或Nginx的404,说明请求根本没到Revel;只有看到500或你手动Abort(404)后才可能走自定义逻辑。
- 确保Nginx配置了
try_files $uri @revel;或proxy_pass把所有非静态路径转发给Revel(如location / { proxy_pass http://127.0.0.1:9000; }) - 禁用Nginx的
error_page 404指令,否则它会劫持本该由Revel处理的404场景 - Revel中真正触发404页的方式是:在控制器里调用
c.Abort(404),或让路由匹配后抛出revel.ERROR_NOT_FOUND
怎么让Revel渲染自定义404.html模板?
Revel通过App.Error函数统一接管错误渲染,但必须配合revel.Intercept和正确返回值才能走模板流程。不能只写render就完事——它默认返回JSON或纯文本。
在app/init.go的init()函数里注册:
revel.InterceptFunc(func(c *revel.Controller) revel.Result {
if c.Response.Status == 404 {
return c.RenderError("404 Not Found")
}
return nil
}, revel.BEFORE, &App{})
然后在app/views/App/下创建404.html(注意路径和命名),内容可含Blade-like语法:{{.Title}}、{{.Message}}等由RenderError传入的字段。
-
RenderError会自动查找views/App/404.html,找不到才回落到默认文本 - 别用
c.RenderTemplate("404")——它不设状态码,也不走错误拦截链 - 模板里避免调用未初始化的
revel.Session或c.Params,否则二次panic导致500
500页面为何总是显示堆栈而不是你的500.html?
Revel默认开启revel.PanicFilter中间件,它捕获panic后直接输出带堆栈的HTML(开发模式)或简单文本(生产模式),完全绕过App.Error和模板渲染。
要启用自定义500页,必须在conf/app.conf里关掉自动panic处理:
results.show.stacktrace = false revel.intercept.panic = false
再配合全局panic恢复逻辑:
revel.InterceptFunc(func(c *revel.Controller) revel.Result {
if c.Response.Status == 500 {
return c.RenderError("Internal Server Error")
}
return nil
}, revel.BEFORE, &App{})
- 关掉
revel.intercept.panic后,panic会冒泡到HTTP handler层,此时需确保你的Web服务器(如Nginx)没用error_page 500覆盖——否则又抢跑了 -
results.show.stacktrace = false防止开发环境意外泄露敏感信息 - 500模板文件名必须是
500.html,放在app/views/App/下,且不能依赖任何可能失败的辅助函数(比如revel.Config.String()未加载时会panic)
为什么本地能显示自定义页,上线后又变回空白或Nginx默认页?
最常被忽略的是Revel的run.mode和http.port配置不一致,以及模板路径权限问题。Revel在prod模式下会预编译模板,但不会校验文件是否存在——缺文件就静默失败。
- 检查
conf/app.conf中run.mode = prod且results.show.stacktrace = false已生效 - 运行
revel run -a yourapp -p 9000 -r时加-v参数看启动日志,确认是否打印Loaded template: views/App/404.html - 确保部署包里
views/App/404.html和500.html真实存在,且文件权限允许Revel进程读取(常见于宝塔或Docker容器内路径挂载遗漏) - 不要依赖
revel.Static提供错误页——它只服务/public下的静态资源,错误页必须由RenderError动态生成


















