Buffalo.Context.Error()不是错误处理入口,它仅写入错误字段而不触发响应;真正生效的是handler返回非nil error,由app.ErrorHandler统一处理。

buffalo.Context.Error() 不是错误处理入口
很多人一上来就查 Error() 方法,以为调用它就能触发全局错误响应逻辑——其实不是。Error() 只是把错误写进 context 的内部 error 字段,不自动渲染、不中断流程、也不走 recovery 中间件。真正起作用的是返回 error 值本身:只要 handler 函数返回非 nil error,Buffalo 就会交由 app.ErrorHandler 处理。
自定义 ErrorHandler 必须替换 app.ErrorHandler
默认的 app.ErrorHandler 会根据环境返回 HTML 错误页或 JSON(开发时带 stack trace),但无法满足统一结构、日志脱敏、状态码映射等需求。必须在 app.go 初始化后显式覆盖:
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
app.ErrorHandler = func(status int, err error, c buffalo.Context) {
if status == 404 {
c.Render(404, r.JSON(map[string]string{"error": "not found"}))
return
}
if errors.Is(err, models.ErrRecordNotFound) {
c.Render(404, r.JSON(map[string]string{"error": "resource not found"}))
return
}
log.Printf("unhandled error %d: %v", status, err)
c.Render(500, r.JSON(map[string]string{"error": "internal server error"}))
}
- 不要在中间件里用
c.Error()模拟错误分发——它不会触发app.ErrorHandler - status 参数来自底层 HTTP 状态码,但 handler 返回的 error 类型才是你做判断的主要依据
- 若需透传原始 error 给日志系统,建议包装为自定义 error 类型(如
AppError{Code: "VALIDATION_FAILED", Status: 400})
panic 捕获被 recovery 中间件吞掉怎么办
Buffalo 默认启用 Recoverer 中间件,它会捕获 panic 并转成 500 响应,但原始 panic stack trace 被隐藏,不利于调试。开发阶段想看到真实 panic,有两个选择:
- 启动时加
--skip-recovery:运行buffalo dev --skip-recovery,panic 直接打到终端 - 改写
app.Use(renders.Middleware)之后的 recovery 行为,在自定义中间件中手动 recover 并 log.Panicln - 生产环境务必保留 recovery,但可在自定义
app.ErrorHandler里对status == 500且err是*runtime.TypeAssertionError等典型 panic 类型做特殊标记
JSON 错误响应结构不一致?用 Render 替代直接 Write
有人在 handler 里直接用 w.WriteHeader() + json.NewEncoder(w).Encode(),结果绕过了 Buffalo 的 content negotiation 和 middleware 链(比如 CORS、gzip)。所有错误响应必须走 c.Render():
-
c.Render(400, r.JSON(map[string]any{"code": "BAD_REQUEST", "message": "xxx"}))才能确保 Content-Type 正确、gzip 生效、中间件不跳过 - 避免在多个地方重复写 JSON 结构,建议封装一个
RenderError(c buffalo.Context, code string, status int, msg string)工具函数 - 注意:Buffalo 的
r.JSON默认不格式化,调试时可临时用r.JSON(&struct{ Code, Msg string }{code, msg})加字段名提升可读性
app.ErrorHandler 里没检查 c.Request().Header.Get("Accept"),导致前端请求 application/json 却返回了 HTML 错误页——Buffalo 不会自动协商错误响应格式,这部分得自己判。

















