必须用e.HTTPErrorHandler注册全局处理器,它需在echo.New()后、e.Start()前设置,通过类型断言echo.HTTPError提取code/message,记录含状态码、原始错误和请求路径的日志,生产环境500+错误需隐藏详情;未匹配路由须用e.Any("/")兜底并调用c.Error(NewHTTPError(404))才能进入该处理器。

必须用 e.HTTPErrorHandler 注册全局处理器,而不是靠中间件 recover() 拦 panic 或手动写 c.JSON(404, ...)。 后者既不记录日志,也不统一响应格式,还绕过环境判断逻辑。
怎么注册自定义 HTTPErrorHandler
注册必须在 echo.New() 之后、e.Start() 之前,且要完全覆盖默认行为。关键不是“加一个函数”,而是确保它能区分错误类型、控制响应内容、记录必要日志。
- 必须显式检查
*echo.HTTPError类型:只有它才能安全提取he.Code和he.Message,其他错误(如fmt.Errorf)会走默认 500 分支 - 生产环境对 500+ 错误要隐藏原始信息:
message := "Something went wrong",避免泄露路径或字段名 - 日志必须包含原始错误、状态码和完整请求路径:
c.Logger().Errorf("HTTP %d: %v | path=%s", code, err, c.Request().URL.Path) - 别漏掉
if he, ok := err.(*echo.HTTPError); ok这个类型断言——这是唯一能拿到业务定义的Code和Message的方式
为什么 c.JSON(404, ...) 不进全局错误处理器
因为它是合法响应,不是错误信号。HTTPErrorHandler 只捕获两类东西:*echo.HTTPError 实例,以及未被 handler 捕获的 panic(需启用 middleware.Recover())。你写的 c.JSON(404, map[string]string{"error": "not found"}) 就是普通响应,框架不会认为它“出错了”。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
- 错误写法:
c.JSON(404, ...)→ 日志不记、文案不统、开发/生产无法差异化 - 正确写法:
c.Error(echo.NewHTTPError(http.StatusNotFound, "user not found"))→ 自动进HTTPErrorHandler,he.Code == 404,he.Message可直接用于日志或响应 - 所有业务层 404 都得走
echo.NewHTTPError构造,不能直接c.Error(fmt.Errorf(...)),否则丢失状态码语义
如何让未匹配路由也进全局错误处理
Echo 默认对未注册路径返回硬编码的 "Not Found" 字符串,这个响应不经过你的 HTTPErrorHandler。要让它进,必须手动加兜底路由,并确保它放在所有 e.GET/e.POST 之后。
- 用
e.Any("/*", ...),不是e.GET("/*", ...),否则PUT、OPTIONS等方法仍绕过 - 兜底 handler 必须返回
c.Error(echo.NewHTTPError(http.StatusNotFound, "route not found")),不能用c.String(404, ...) - 这个
e.Any必须是最后一条路由注册——如果前面有e.GET("/*", ...),真实业务路由会被遮蔽 - 日志里要单独标出是“未匹配路由”:
c.Logger().Errorf("404 route not found | path=%s method=%s", ...)
真正容易被忽略的是:404 和 500 在日志里要分开处理,但响应文案不能都用 he.Message。404 的 he.Message 很可能来自用户输入(比如 /user/:id 中传了非法 ID),直接返回可能暴露内部逻辑;而 500 的堆栈只该在开发环境出现,生产环境连 he.Message 都不该透出。










