响应错误#
返回 HTTP 错误#
处理函数可以返回错误而不是成功的响应。有许多实用函数可以返回常见的 HTTP 错误:
huma.Register(api, huma.Operation{
OperationID: "get-thing",
Method: http.MethodGet,
Path: "/things/{thing-id}",
Summary: "Get a thing by ID",
}, func(ctx context.Context, input ThingRequest) (*struct{}, error) {
// Return a 404 Not Found error
return nil, huma.Error404NotFound("thing not found")
}
这些错误函数的命名方式类似于 Error{code}{name},并接受一条消息和错误细节,这些细节可以向用户提供更多信息。例如,huma.Error400BadRequest(msg string, errs ...error)。像 VSCode 这样的编辑器应该会在您输入时自动显示可用的错误:

默认错误响应
如果返回的错误没有关联的 HTTP 状态码,例如您使用 fmt.Errorf("my error"),则默认错误响应码为 500 Internal Server Error。使用 huma.NewError 来返回带有自定义状态码的错误。
错误模型#
错误使用 RFC 9457 Problem Details for HTTP APIs,内容类型类似于 application/problem+json,并返回一个结构,如下所示:
HTTP/2.0 422 Unprocessable Entity
Cache-Control: private
Content-Length: 241
Content-Type: application/problem+json
Link: </schemas/ErrorModel.json>; rel="describedBy"
{
"$schema": "https://api.rest.sh/schemas/ErrorModel.json",
"status": 422,
"title": "Unprocessable Entity",
"detail": "validation failed",
"errors": [
{
"location": "body.title",
"message": "expected string",
"value": true
},
{
"location": "body.reviews",
"message": "unexpected property",
"value": {
"reviews": 5,
"title": true
}
}
]
}
errors 字段是可选的,可能包含有关特定发生错误的更多细节。有关更多细节,请参阅 huma.ErrorModel。
要在 errors 数组中显示 location、message 和 value,请使用 huma.ErrorDetail 结构体。如果您需要出于任何原因用自定义逻辑包装它,可以实现 huma.ErrorDetailer 接口。
详尽错误#
推荐尽可能返回详尽错误,以防止用户因反复重试无效请求而感到沮丧,每次都得到不同的错误。
输入参数验证、主体验证、解析器等都支持返回详尽错误。因此,更倾向于在操作处理程序中使用它们,而不是自定义错误逻辑。
错误状态码#
虽然 Huma 会尽一切努力返回详尽错误,但每个单独响应只能包含一个 HTTP 状态码。下面的图表描述了返回哪些代码以及何时返回:
flowchart TD
Request[Request has errors?] -->|yes| Panic
Request -->|no| Continue[Continue to handler]
Panic[Panic?] -->|yes| 500
Panic -->|no| RequestBody[Request body too large?]
RequestBody -->|yes| 413
RequestBody -->|no| RequestTimeout[Request took too long to read?]
RequestTimeout -->|yes| 408
RequestTimeout -->|no| ParseFailure[Cannot parse input?]
ParseFailure -->|yes| 400
ParseFailure -->|no| ValidationFailure[Validation failed?]
ValidationFailure -->|yes| 422
ValidationFailure -->|no| 400
这意味着例如,可能收到一个 HTTP 408 Request Timeout 响应,同时其中还包含一个输入标头验证错误的错误细节。由于请求超时优先级更高,因此将返回该响应状态码。
错误标头#
中间件可用于向所有响应添加标头,例如用于缓存控制、速率限制等。对于特定于错误或特定处理程序错误响应的标头,您可以根据需要用附加标头包装错误:
return nil, huma.ErrorWithHeaders(
huma.Error404NotFound("thing not found"),
http.Header{
"Cache-Control": {"no-store"},
},
)
多次调用 huma.ErrorWithHeaders 是安全的,所有传递的标头将附加到任何现有标头。
任何满足 huma.HeadersError 接口的错误都会将标头添加到响应中。
自定义错误#
可以提供您自己的错误模型,并让内置的错误实用函数使用该模型而不是默认模型。这在您希望在错误响应中提供更多信息,或者您的组织对错误响应结构有要求时很有用。
这是通过将您的自定义模型定义为 huma.StatusError,然后覆盖内置的 huma.NewError 函数来实现的:
type MyError struct {
status int
Message string `json:"message"`
Details []string `json:"details,omitempty"`
}
func (e *MyError) Error() string {
return e.Message
}
func (e *MyError) GetStatus() int {
return e.status
}
func main() {
huma.NewError = func(status int, message string, errs ...error) huma.StatusError {
details := make([]string, len(errs))
for i, err := range errs {
details[i] = err.Error()
}
return &MyError{
status: status,
Message: message,
Details: details,
}
}
router := chi.NewMux()
api := humachi.New(router, huma.DefaultConfig("My API", "1.0.0"))
huma.Register(api, huma.Operation{
OperationID: "get-error",
Method: http.MethodGet,
Path: "/error",
}, func(ctx context.Context, i *struct{}) (*struct{}, error) {
return nil, huma.Error404NotFound("not found", fmt.Errorf("some-other-error"))
})
http.ListenAndServe(":8888", router)
}
要更改返回的默认内容类型,您还可以实现 huma.ContentTypeFilter 接口。
深入了解#
- 参考
huma.ErrorModel默认错误模型huma.ErrorDetail描述错误的 location 和 valuehuma.StatusError用于自定义错误的接口huma.HeadersError用于带标头的错误的接口huma.ContentTypeFilter用于自定义内容类型的接口
- 外部链接