85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
// Package errors 定义业务错误类型与哨兵错误。
|
|
// 业务错误携带可被前端消费的业务码(Code),并支持 errors.As 提取。
|
|
package errors
|
|
|
|
import (
|
|
stderrors "errors"
|
|
"fmt"
|
|
)
|
|
|
|
// BizError 是带业务码的业务错误。
|
|
type BizError struct {
|
|
Code int
|
|
Msg string
|
|
Err error
|
|
}
|
|
|
|
func (e *BizError) Error() string {
|
|
if e.Err != nil {
|
|
return fmt.Sprintf("%s: %v", e.Msg, e.Err)
|
|
}
|
|
return e.Msg
|
|
}
|
|
|
|
func (e *BizError) Unwrap() error { return e.Err }
|
|
|
|
// New 构造一个不带原始 error 的业务错误。
|
|
func New(code int, msg string) *BizError {
|
|
return &BizError{Code: code, Msg: msg}
|
|
}
|
|
|
|
// Wrap 在传播错误时附加上下文与业务码,保留错误链路。
|
|
func Wrap(code int, msg string, err error) *BizError {
|
|
return &BizError{Code: code, Msg: msg, Err: err}
|
|
}
|
|
|
|
// Is 判断 err 链中是否包含 target,语义与标准库 errors.Is 一致。
|
|
// 它沿 Unwrap 链遍历,因此能正确识别被 Wrap 包装后的目标错误
|
|
// (如 gorm.ErrRecordNotFound 或本包的哨兵错误 ErrNotFound)。
|
|
func Is(err, target error) bool {
|
|
return stderrors.Is(err, target)
|
|
}
|
|
|
|
// 常用哨兵错误,供各层直接引用。
|
|
var (
|
|
ErrBadRequest = New(40000, "bad request")
|
|
ErrUnauthorized = New(40100, "unauthorized")
|
|
ErrForbidden = New(40300, "forbidden")
|
|
ErrNotFound = New(40400, "not found")
|
|
ErrServer = New(50000, "internal server error")
|
|
)
|
|
|
|
// CodeOf 从 err 中提取业务码,非业务错误返回 50000。
|
|
func CodeOf(err error) int {
|
|
var be *BizError
|
|
if err != nil && asBizError(err, &be) {
|
|
return be.Code
|
|
}
|
|
return 50000
|
|
}
|
|
|
|
// MsgOf 从 err 中提取可读消息,非业务错误返回内部错误提示。
|
|
func MsgOf(err error) string {
|
|
var be *BizError
|
|
if err != nil && asBizError(err, &be) {
|
|
return be.Msg
|
|
}
|
|
return "internal server error"
|
|
}
|
|
|
|
// asBizError 兼容被 fmt.Errorf("%w") 包装后的 BizError。
|
|
func asBizError(err error, target **BizError) bool {
|
|
for err != nil {
|
|
if b, ok := err.(*BizError); ok {
|
|
*target = b
|
|
return true
|
|
}
|
|
u, ok := err.(interface{ Unwrap() error })
|
|
if !ok {
|
|
return false
|
|
}
|
|
err = u.Unwrap()
|
|
}
|
|
return false
|
|
}
|