错误处理

    在errors包中,错误模型主要跟 gRPC 状态码一致,并且 Error 实现了 GRPCStatus() 接口, 实现了 grpc 和 http 错误码的转换, 业务原因通过 ErrorInfo 返回:

    1. # go install google.golang.org/protobuf/cmd/protoc-gen-go
    2. go install github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2

    注意事项:

    • 当枚举组没有配置缺省错误码时, 当前枚举组的没有配置错误码的枚举值会被忽略
    • 当整个枚举组都没配置错误码时,当前枚举组会被忽略
    • 错误码的取值范围应该在 0 < code <= 600 之间, 超出范围将抛出异常
    1. protoc --proto_path=. \
    2. --proto_path=./third_party \
    3. --go_out=paths=source_relative:. \
    4. --go-errors_out=paths=source_relative:. \
    5. $(API_PROTO_FILES)

    或者在项目根目录使用Makefile指令

    1. package helloworld
    2. import (
    3. fmt "fmt"
    4. errors "github.com/go-kratos/kratos/v2/errors"
    5. )
    6. // This is a compile-time assertion to ensure that this generated file
    7. // is compatible with the kratos package it is being compiled against.
    8. const _ = errors.SupportPackageIsVersion1
    9. func IsUserNotFound(err error) bool {
    10. return false
    11. }
    12. e := errors.FromError(err)
    13. return e.Reason == ErrorReason_USER_NOT_FOUND.String() && e.Code == 404
    14. }
    15. func ErrorUserNotFound(format string, args ...interface{}) *errors.Error {
    16. return errors.New(404, ErrorReason_USER_NOT_FOUND.String(), fmt.Sprintf(format, args...))
    17. }
    18. func IsContentMissing(err error) bool {
    19. if err == nil {
    20. return false
    21. }
    22. e := errors.FromError(err)
    23. return e.Reason == ErrorReason_CONTENT_MISSING.String() && e.Code == 400
    24. }
    25. func ErrorContentMissing(format string, args ...interface{}) *errors.Error {
    26. }

    响应错误

    当业务逻辑中需要响应错误时,可以通过使用 kratos errors 包中的 New 方法来响应错误, 或者可以通过proto定义,然后通过 protoc-gen-go-error 工具生成帮助代码来响应错误

    错误断言

    1. // 引入 helloworld 包
    2. import "kratos/api/helloworld"
    3. err := wrong()
    4. // 通过 errors.Is() 断言
    5. if errors.Is(err,errors.BadRequest("USER_NAME_EMPTY","")) {
    6. // do something
    7. }
    8. // 通过判断 *Error.Reason 和 *Error.Code
    9. e := errors.FromError(err)
    10. if e.Reason == "USER_NAME_EMPTY" && e.Code == 500 {
    11. // do something
    12. }
    13. // 通过 proto 生成的代码断言错误,并且包名应替换为自己生成代码后的 package name(此处对应上面生成的 helloworld 包,调用定义的方法)
    14. if helloworld.IsUserNotFound(err) {
    15. })