Revel框架错误页面仅在开发模式下自动显示带堆栈的友好错误页;生产环境下需在app/views/errors/下显式提供404.html、500.html等模板,且仅支持.error、.flash、.request变量,不经过Controller,无法访问自定义数据。

Revel 框架的错误页面默认只在开发模式下显示带堆栈的友好编译错误页;生产环境(REVEL_RUNMODE=prod)下它不会自动渲染任何 HTML 错误页——你必须显式提供模板,否则 500/404 等错误会返回空响应或默认 HTTP 错误文本。
app/views/errors/ 下放模板就能生效
Revel 会按约定路径查找错误模板:app/views/errors/404.html、app/views/errors/500.html 等。只要文件存在且命名正确,框架会在对应状态码时自动渲染它。
- 模板路径必须严格为
app/views/errors/{status}.html(小写,无空格),不能是error/404.html或errors/404.tpl - 模板中可直接使用 Revel 提供的上下文变量:
.errors(验证错误)、.flash(上个请求的 flash 数据) - 不支持嵌套 layout:错误模板是独立渲染的,
{{yield}}在这里无效;若需复用页眉页脚,得用{{include "header.html"}}手动包含 - 确保模板语法合法——比如
{{if .errors.booking.CheckInDate}}前要先{{with $errors := .errors}}避免 nil 指针 panic
错误模板里访问不到 Controller 的数据
Revel 的错误模板由框架内部触发渲染,不经过任何 Controller Action,因此你无法在 errors/500.html 中使用 .User、.Title 这类自定义变量——它们根本不在渲染上下文中。
- 唯一可用的预置变量只有:
.errors、.flash和.request(含 URL、Method 等基础信息) - 如果需要透传额外字段(如当前语言、站点名),只能通过中间件注入:
revel.InterceptFunc+c.RenderArgs["site_name"] = "MyApp" - 注意:这种注入对所有模板生效,包括 errors/,但要在
PanicFilter之后、ActionInvoker之前注册,否则 500 场景下可能未执行到
500 页面不显示实际错误原因?检查 PanicFilter 行为
Revel 默认用 PanicFilter 捕获 panic 并渲染 errors/500.html,但它**不会把 panic 错误信息自动塞进 .errors 或其他变量里**——除非你手动处理。
- 开发模式下能看到详细堆栈,是因为
PanicFilter走了另一条 debug 渲染逻辑;生产模式下它只清空 panic,然后跳转模板 - 若想在 500 页面显示简要错误(如
"database connection failed"),需自定义PanicFilter替换原版,或在app/init.go中重写:
// app/init.go
revel.InterceptFunc(func(c *revel.Controller, fc []revel.FilterConfig) revel.Result {
if c.Result != nil && c.Result.Status() == 500 {
c.RenderArgs["panic_msg"] = c.Panic.Error()
}
return nil
}, revel.BEFORE_ACTION)
- 然后在
errors/500.html中用{{.panic_msg}}输出(注意 XSS 风险,建议{{.panic_msg | safe}}或提前过滤)
Nginx 层 error_page 会覆盖 Revel 的错误模板
如果你在 Nginx 配置里写了 error_page 500 /500.html;,那无论 Revel 是否渲染了 errors/500.html,Nginx 都会拦截响应并返回自己的静态文件——Revel 的模板完全不会被调用。
- 这是常见线上事故点:本地调试正常,部署后 500 页面变成 Nginx 默认页
- 检查 Nginx 配置是否含
error_page指令;若有,要么删掉它,要么确保其指向的文件与 Revel 模板内容一致 - 更稳妥的做法是:Nginx 不配
error_page,让 Revel 全权处理,再通过反向代理透传真实状态码(proxy_intercept_errors off;必须关闭)
真正容易被忽略的是:Revel 的错误模板机制只对框架内抛出的 404(路由未匹配)和 panic 导致的 500 生效;如果 Controller 主动返回 c.RenderError(500) 或 c.Abort(500),它走的是普通响应流程,不会触发 errors/500.html 渲染——这时候得靠你自己的逻辑判断并显式 c.RenderTemplate("errors/500.html")。


















