跳至主要內容

错误处理

Ryan SU大约 6 分钟

错误类型

simple admin 有三种错误类型

  • ApiError : Api 错误,用于返回带 http 状态码的错误返回信息
  • CodeError : 业务代码类型错误, 错误状态码统一为 200, 详细状态码在返回体中
  • Status Error: RPC 错误

RPC 错误

status.Error(codes.Internal, result.Error.Error())

直接 return status.Error

简便方法

errorx.NewInternalError(msg)

errorx.NewInvalidArgumentError(msg)

errorx.NewNotFoundError(msg)

errorx.NewAlreadyExistsError(msg)

errorx.NewUnauthenticatedError

业务码错误

使用 CodeError 返回 API 层的业务码错误,

errorx.CodeError(enum.InvalidArgument, "Please log in")

简便方法


func NewCodeCanceledError(msg string) error {
 return &CodeError{Code: 1, Msg: msg}
}

func NewCodeInvalidArgumentError(msg string) error {
 return &CodeError{Code: 3, Msg: msg}
}

func NewCodeNotFoundError(msg string) error {
 return &CodeError{Code: 5, Msg: msg}
}

func NewCodeAlreadyExistsError(msg string) error {
 return &CodeError{Code: 6, Msg: msg}
}

func NewCodeAbortedError(msg string) error {
 return &CodeError{Code: 10, Msg: msg}
}

func NewCodeInternalError(msg string) error {
 return &CodeError{Code: 13, Msg: msg}
}

func NewCodeUnavailableError(msg string) error {
 return &CodeError{Code: 14, Msg: msg}
}

func NewDefaultError(msg string) error {
 return NewCodeError(defaultCode, msg)
}

错误码

所有的错误码都放在 github.com/suyuan32/simple-admin-common/enum/errorcode 中, 默认前 17 个错误码与 grpc 保持一致, 你也可以自己添加错误码

package enum

const (
 // OK is returned on success.
 OK int = 0

 // Canceled indicates the operation was canceled (typically by the caller).
 //
 // The gRPC framework will generate this error code when cancellation
 // is requested.
 Canceled int = 1

 // Unknown error. An example of where this error may be returned is
 // if a Status value received from another address space belongs to
 // an error-space that is not known in this address space. Also
 // errors raised by APIs that do not return enough error information
 // may be converted to this error.
 //
 // The gRPC framework will generate this error code in the above two
 // mentioned cases.
 Unknown int = 2

 // InvalidArgument indicates client specified an invalid argument.
 // Note that this differs from FailedPrecondition. It indicates arguments
 // that are problematic regardless of the state of the system
 // (e.g., a malformed file name).
 //
 // This error code will not be generated by the gRPC framework.
 InvalidArgument int = 3

 // DeadlineExceeded means operation expired before completion.
 // For operations that change the state of the system, this error may be
 // returned even if the operation has completed successfully. For
 // example, a successful response from a server could have been delayed
 // long enough for the deadline to expire.
 //
 // The gRPC framework will generate this error code when the deadline is
 // exceeded.
 DeadlineExceeded int = 4

 // NotFound means some requested entity (e.g., file or directory) was
 // not found.
 //
 // This error code will not be generated by the gRPC framework.
 NotFound int = 5

 // AlreadyExists means an attempt to create an entity failed because one
 // already exists.
 //
 // This error code will not be generated by the gRPC framework.
 AlreadyExists int = 6

 // PermissionDenied indicates the caller does not have permission to
 // execute the specified operation. It must not be used for rejections
 // caused by exhausting some resource (use ResourceExhausted
 // instead for those errors). It must not be
 // used if the caller cannot be identified (use Unauthenticated
 // instead for those errors).
 //
 // This error code will not be generated by the gRPC core framework,
 // but expect authentication middleware to use it.
 PermissionDenied int = 7

 // ResourceExhausted indicates some resource has been exhausted, perhaps
 // a per-user quota, or perhaps the entire file system is out of space.
 //
 // This error code will be generated by the gRPC framework in
 // out-of-memory and server overload situations, or when a message is
 // larger than the configured maximum size.
 ResourceExhausted int = 8

 // FailedPrecondition indicates operation was rejected because the
 // system is not in a state required for the operation's execution.
 // For example, directory to be deleted may be non-empty, an rmdir
 // operation is applied to a non-directory, etc.
 //
 // A litmus test that may help a service implementor in deciding
 // between FailedPrecondition, Aborted, and Unavailable:
 //  (a) Use Unavailable if the client can retry just the failing call.
 //  (b) Use Aborted if the client should retry at a higher-level
 //      (e.g., restarting a read-modify-write sequence).
 //  (c) Use FailedPrecondition if the client should not retry until
 //      the system state has been explicitly fixed. E.g., if an "rmdir"
 //      fails because the directory is non-empty, FailedPrecondition
 //      should be returned since the client should not retry unless
 //      they have first fixed up the directory by deleting files from it.
 //  (d) Use FailedPrecondition if the client performs conditional
 //      REST Get/Update/Delete on a resource and the resource on the
 //      server does not match the condition. E.g., conflicting
 //      read-modify-write on the same resource.
 //
 // This error code will not be generated by the gRPC framework.
 FailedPrecondition int = 9

 // Aborted indicates the operation was aborted, typically due to a
 // concurrency issue like sequencer check failures, transaction aborts,
 // etc.
 //
 // See litmus test above for deciding between FailedPrecondition,
 // Aborted, and Unavailable.
 //
 // This error code will not be generated by the gRPC framework.
 Aborted int = 10

 // OutOfRange means operation was attempted past the valid range.
 // E.g., seeking or reading past end of file.
 //
 // Unlike InvalidArgument, this error indicates a problem that may
 // be fixed if the system state changes. For example, a 32-bit file
 // system will generate InvalidArgument if asked to read at an
 // offset that is not in the range [0,2^32-1], but it will generate
 // OutOfRange if asked to read from an offset past the current
 // file size.
 //
 // There is a fair bit of overlap between FailedPrecondition and
 // OutOfRange. We recommend using OutOfRange (the more specific
 // error) when it applies so that callers who are iterating through
 // a space can easily look for an OutOfRange error to detect when
 // they are done.
 //
 // This error code will not be generated by the gRPC framework.
 OutOfRange int = 11

 // Unimplemented indicates operation is not implemented or not
 // supported/enabled in this service.
 //
 // This error code will be generated by the gRPC framework. Most
 // commonly, you will see this error code when a method implementation
 // is missing on the server. It can also be generated for unknown
 // compression algorithms or a disagreement as to whether an RPC should
 // be streaming.
 Unimplemented int = 12

 // Internal errors. Means some invariants expected by underlying
 // system has been broken. If you see one of these errors,
 // something is very broken.
 //
 // This error code will be generated by the gRPC framework in several
 // internal error conditions.
 Internal int = 13

 // Unavailable indicates the service is currently unavailable.
 // This is a most likely a transient condition and may be corrected
 // by retrying with a backoff. Note that it is not always safe to retry
 // non-idempotent operations.
 //
 // See litmus test above for deciding between FailedPrecondition,
 // Aborted, and Unavailable.
 //
 // This error code will be generated by the gRPC framework during
 // abrupt shutdown of a server process or network connection.
 Unavailable int = 14

 // DataLoss indicates unrecoverable data loss or corruption.
 //
 // This error code will not be generated by the gRPC framework.
 DataLoss int = 15

 // Unauthenticated indicates the request does not have valid
 // authentication credentials for the operation.
 //
 // The gRPC framework will generate this error code when the
 // authentication metadata is invalid or a Credentials callback fails,
 // but also expect authentication middleware to generate it.
 Unauthenticated int = 16
)

Api 错误

errorx.NewApiError(httpCode, msg)

简便方法


func NewApiErrorWithoutMsg(code int) error {
 return &ApiError{Code: code, Msg: ""}
}

func NewApiInternalError(msg string) error {
 return &ApiError{Code: http.StatusInternalServerError, Msg: msg}
}

func NewApiBadRequestError(msg string) error {
 return &ApiError{Code: http.StatusBadRequest, Msg: msg}
}

func NewApiUnauthorizedError(msg string) error {
 return &ApiError{Code: http.StatusUnauthorized, Msg: msg}
}

func NewApiForbiddenError(msg string) error {
 return &ApiError{Code: http.StatusForbidden, Msg: msg}
}

func NewApiNotFoundError(msg string) error {
 return &ApiError{Code: http.StatusNotFound, Msg: msg}
}

func NewApiBadGatewayError(msg string) error {
 return &ApiError{Code: http.StatusBadGateway, Msg: msg}
}

注意

所有错误都会被自动翻译, 不为 0 的错误会在前端产生弹窗, 通过 api ErrorMessageMode 控制

在生成 Api 的时候使用 --trans_err=true 会在 handler 使用翻译

goctls api go --api ./api/desc/core.api --dir ./api --trans_err=true
package api

import (
	"net/http"

	"github.com/zeromicro/go-zero/rest/httpx"

	"github.com/suyuan32/simple-admin-core/api/internal/logic/api"
	"github.com/suyuan32/simple-admin-core/api/internal/svc"
	"github.com/suyuan32/simple-admin-core/api/internal/types"
)

// swagger:route post /api/create api CreateApi
//
// Create API information | 创建API
//
// Create API information | 创建API
//
// Parameters:
//  + name: body
//    require: true
//    in: body
//    type: ApiInfo
//
// Responses:
//  200: BaseMsgResp

func CreateApiHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req types.ApiInfo
		if err := httpx.Parse(r, &req, true); err != nil {
			httpx.ErrorCtx(r.Context(), w, err)
			return
		}

		l := api.NewCreateApiLogic(r.Context(), svcCtx)
		resp, err := l.CreateApi(&req)
		if err != nil {
			err = svcCtx.Trans.TransError(r.Context(), err)
			httpx.ErrorCtx(r.Context(), w, err)
		} else {
			httpx.OkJsonCtx(r.Context(), w, resp)
		}
	}
}

err = svcCtx.Trans.TransError(r.Context(), err)

注意

CodeError 是将错误码写在返回体中,返回的状态全部为 200 StatusOK, 若需要返回带 http 请求状态码的错误信息,请使用 errorx.ApiError.