跳转到内容

错误处理

Echo 提倡集中式错误处理:处理函数和中间件返回 error,由单一错误处理函数将其转换为 HTTP 响应。这样可以把日志记录和响应格式化放在同一个位置。

返回普通 error*echo.HTTPError

e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) error {
if !authenticated(c) {
// invalid credentials → abort with 401
return echo.NewHTTPError(http.StatusUnauthorized, "Please provide valid credentials")
}
return next(c)
}
})

没有消息的 echo.NewHTTPError(code) 会使用状态文本(例如 "Unauthorized")。 Echo 还提供 echo.ErrBadRequestecho.ErrNotFoundecho.ErrUnauthorized 等哨兵错误。

Echo 的默认处理函数以 JSON 响应:

{ "message": "error connecting to redis" }

普通 error 会变成 500 Internal Server Error(在暴露错误运行时会包含原始消息)。 *HTTPError 会使用自身的状态码和消息。

通过 e.HTTPErrorHandler 设置你自己的处理函数,这适用于错误页面、通知, 或把错误发送到集中式系统。

使用 echo.UnwrapResponse() 检查响应是否已经发送,并通过 echo.HTTPStatusCoder 在错误链中查找状态码:

func customHTTPErrorHandler(c *echo.Context, err error) {
if resp, uErr := echo.UnwrapResponse(c.Response()); uErr == nil {
if resp.Committed {
return // already sent by a handler/middleware
}
}
code := http.StatusInternalServerError
var sc echo.HTTPStatusCoder
if errors.As(err, &sc) {
if tmp := sc.StatusCode(); tmp != 0 {
code = tmp
}
}
var cErr error
if c.Request().Method == http.MethodHead {
cErr = c.NoContent(code)
} else {
cErr = c.File(fmt.Sprintf("%d.html", code)) // e.g. 404.html, 500.html
}
if cErr != nil {
c.Logger().Error("failed to send error page", "error", errors.Join(err, cErr))
}
}
e.HTTPErrorHandler = customHTTPErrorHandler