buffalo框架需手动接管404和500错误:重写app.notfound处理路由404,用自定义recover500中间件捕获panic并渲染html;静态资源404和api错误需单独处理,中间件顺序至关重要。

http.Error 和内置错误模板,但不直接支持像 Rails 那样开箱即用的 404/500 页面自动路由接管。要真正生效自定义错误页面,关键不是“加个模板”,而是**绕过默认 panic 捕获逻辑、接管 HTTP 状态码响应流程**。
为什么 app.ErrorHandler 不生效?
Buffalo 的 app.ErrorHandler 仅处理中间件链中显式调用 c.Error() 的场景(比如你手动 c.Error(404, errors.New("not found"))),对路由未匹配(404)或 panic 导致的 500 完全无效。底层仍走 Go 标准库的 http.Error,直接写入响应体并终止中间件链。
接管 404:必须重写 app.NotFound 函数
Buffalo 在启动时会将未匹配路由委托给 app.NotFound,它默认返回纯文本 "404 Not Found"。你需要替换为一个返回 HTML 响应的函数:
- 在
app.go初始化后、app.Serve()前插入:app.NotFound = func(c buffalo.Context) error { return c.Render(404, r.HTML("errors/404.plush.html")) } - 确保
templates/errors/404.plush.html存在,且路径拼写准确(Buffalo 对大小写和下划线敏感) - 不要在该函数里调用
c.Error(404, ...)—— 这会再次触发默认行为
捕获 500:必须用中间件 wrap panic 并 render
Buffalo 的 panic 恢复中间件(buffalo.WrapRecovery)只打印日志,不提供自定义响应。你需要自己写一个中间件:
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
- 创建
middleware/recover.go:func Recover500(next buffalo.Handler) buffalo.Handler { return func(c buffalo.Context) error { defer func() { if r := recover(); r != nil { c.Response().WriteHeader(500) c.Render(500, r.HTML("errors/500.plush.html")) return } }() return next(c) } } - 在
app.go中注册:app.Use(Recover500)
,且必须放在所有其他中间件之前(否则 panic 可能被上游截断) - 注意:此中间件无法捕获异步 goroutine 中的 panic,仅限主请求协程
静态文件 404 和 API 错误需单独处理
Buffalo 的 app.Static 路由不经过 app.NotFound,所以 /assets/xxx.js 404 仍显示默认文本。解决方法只有两个:
- 改用
http.FileServer手动包装,检查os.Stat后 fallback 到自定义页面(复杂,不推荐) - 接受现实:静态资源 404 就让它保持简洁文本,重点保障 HTML 路由的体验
另外,JSON API 接口(如 /api/users)出错时,不应返回 HTML 页面,而应统一用 c.Render(500, r.JSON(...)) —— 这类错误必须在业务 handler 内部显式处理,不能依赖全局 500 页面。










