78 lines
1.9 KiB
Go
78 lines
1.9 KiB
Go
package errcode
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
// Error 业务错误
|
|
type Error struct {
|
|
code int
|
|
msg string
|
|
details []string
|
|
}
|
|
|
|
// codes 用于注册时去重检查
|
|
var codes = map[int]string{}
|
|
|
|
// NewError 注册并创建一个错误码
|
|
func NewError(code int, msg string) *Error {
|
|
if _, exists := codes[code]; exists {
|
|
panic(fmt.Sprintf("error code %d already exists, please change", code))
|
|
}
|
|
codes[code] = msg
|
|
return &Error{code: code, msg: msg}
|
|
}
|
|
|
|
func (e *Error) Error() string {
|
|
return fmt.Sprintf("error code: %d, msg: %s", e.code, e.msg)
|
|
}
|
|
|
|
func (e *Error) Code() int { return e.code }
|
|
func (e *Error) Msg() string { return e.msg }
|
|
func (e *Error) Details() []string { return e.details }
|
|
|
|
func (e *Error) Msgf(args ...interface{}) string {
|
|
return fmt.Sprintf(e.msg, args...)
|
|
}
|
|
|
|
// WithDetails 附加详细信息(返回副本)
|
|
func (e *Error) WithDetails(details ...string) *Error {
|
|
newError := *e
|
|
newError.details = append(newError.details, details...)
|
|
return &newError
|
|
}
|
|
|
|
// StatusCode 业务码 → HTTP 状态码
|
|
// 仅对少数特殊错误返回非 200,其余统一 200,由前端按业务 code 处理
|
|
func (e *Error) StatusCode() int {
|
|
switch e.code {
|
|
case Success.Code():
|
|
return http.StatusOK
|
|
|
|
// 鉴权类返回 401,便于前端拦截器统一处理跳转登录
|
|
case Unauthorized.Code(),
|
|
UnauthorizedTokenError.Code(),
|
|
UnauthorizedTokenTimeout.Code(),
|
|
UnauthorizedTokenMissing.Code():
|
|
return http.StatusUnauthorized
|
|
|
|
// 越权/无权限返回 403,便于网关与审计识别越权事件
|
|
case Forbidden.Code():
|
|
return http.StatusForbidden
|
|
|
|
// 限流返回 429,便于网关识别限流事件
|
|
case TooManyRequests.Code():
|
|
return http.StatusTooManyRequests
|
|
|
|
// 系统错误返回 500,便于运维监控告警
|
|
case ServerError.Code(),
|
|
DatabaseError.Code(),
|
|
CacheError.Code(),
|
|
RPCError.Code(),
|
|
UnknownError.Code():
|
|
return http.StatusInternalServerError
|
|
}
|
|
return http.StatusOK
|
|
}
|