You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.4 KiB
154 lines
4.4 KiB
package rs
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
// ErrOK 表示没有任何错误。
|
|
// 对应 HTTP 响应状态码为 500。
|
|
ErrOK = NewError(http.StatusOK, 0, "OK")
|
|
|
|
// ErrInternal 客户端请求有效,但服务器处理时发生了意外。
|
|
// 对应 HTTP 响应状态码为 500。
|
|
ErrInternal = NewError(http.StatusInternalServerError, -100, "系统内部错误")
|
|
|
|
// ErrServiceUnavailable 服务器无法处理请求,一般用于网站维护状态。
|
|
// 对应 HTTP 响应状态码为 503。
|
|
ErrServiceUnavailable = NewError(http.StatusServiceUnavailable, -101, "服务不可用")
|
|
|
|
// ErrUnauthorized 用户未提供身份验证凭据,或者没有通过身份验证。
|
|
// 响应的 HTTP 状态码为 401。
|
|
ErrUnauthorized = NewError(http.StatusUnauthorized, -102, "身份验证失败")
|
|
|
|
// ErrForbidden 用户通过了身份验证,但是不具有访问资源所需的权限。
|
|
// 响应的 HTTP 状态码为 403。
|
|
ErrForbidden = NewError(http.StatusForbidden, -103, "不具有访问资源所需的权限")
|
|
|
|
// ErrGone 所请求的资源已从这个地址转移,不再可用。
|
|
// 响应的 HTTP 状态码为 410。
|
|
ErrGone = NewError(http.StatusGone, -104, "所请求的资源不存在")
|
|
|
|
// ErrUnsupportedMediaType 客户端要求的返回格式不支持。
|
|
// 比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式。
|
|
// 响应的 HTTP 状态码为 415。
|
|
ErrUnsupportedMediaType = NewError(http.StatusUnsupportedMediaType, -105, "请求的数据格式错误")
|
|
|
|
// ErrUnprocessableEntity 无法处理客户端上传的附件,导致请求失败。
|
|
// 响应的 HTTP 状态码为 422。
|
|
ErrUnprocessableEntity = NewError(http.StatusUnprocessableEntity, -106, "上传了不被支持的附件")
|
|
|
|
// ErrTooManyRequests 客户端的请求次数超过限额。
|
|
// 响应的 HTTP 状态码为 429。
|
|
ErrTooManyRequests = NewError(http.StatusTooManyRequests, -107, "请求次数超过限额")
|
|
|
|
// ErrSeeOther 表示需要参考另一个 URL 才能完成接收的请求操作,
|
|
// 当请求方式使用 POST、PUT 和 DELETE 时,对应的 HTTP 状态码为 303,
|
|
// 其它的请求方式在大多数情况下应该使用 400 状态码。
|
|
ErrSeeOther = NewError(http.StatusSeeOther, -108, "需要更进一步才能完成操作")
|
|
|
|
// ErrBadRequest 服务器不理解客户端的请求。
|
|
// 对应 HTTP 状态码为 400。
|
|
ErrBadRequest = NewError(http.StatusBadRequest, -109, "请求错误")
|
|
|
|
// ErrBadParams 客户端提交的参数不符合要求
|
|
// 对应 HTTP 状态码为 400。
|
|
ErrBadParams = NewError(http.StatusBadRequest, -110, "参数错误")
|
|
|
|
// ErrRecordNotFound 访问的数据不存在
|
|
// 对应 HTTP 状态码为 404。
|
|
ErrRecordNotFound = NewError(http.StatusNotFound, -111, "访问的数据不存在")
|
|
)
|
|
|
|
type Error struct {
|
|
// 被包装的错误对象
|
|
internal error
|
|
// 响应的 HTTP 状态码
|
|
status int
|
|
// 错误码
|
|
code int
|
|
// 错误提示消息
|
|
text string
|
|
// 错误携带的响应数据
|
|
data any
|
|
}
|
|
|
|
func NewError(status, code int, text string) *Error {
|
|
return &Error{nil, status, code, text, nil}
|
|
}
|
|
|
|
// Code 返回错误码
|
|
func (e *Error) Code() int {
|
|
return e.code
|
|
}
|
|
|
|
// Text 返回错误提示
|
|
func (e *Error) Text() string {
|
|
return e.text
|
|
}
|
|
|
|
// Data 返回携带的数据
|
|
func (e *Error) Data() any {
|
|
return e.data
|
|
}
|
|
|
|
// Internal 返回原始错误
|
|
func (e *Error) Internal() error {
|
|
return e.internal
|
|
}
|
|
|
|
// Unwrap 支持 errors.Unwrap() 方法
|
|
func (e *Error) Unwrap() error {
|
|
return e.Internal()
|
|
}
|
|
|
|
// WithInternal 通过实际错误对象派生新的实例
|
|
func (e *Error) WithInternal(err error) *Error {
|
|
// 由于错误比较复杂,不好做完全等于,
|
|
// 在这里就直接复制当前对象
|
|
c := *e
|
|
c.internal = err
|
|
return &c
|
|
}
|
|
|
|
// WithStatus 通过 HTTP 状态码派生新的实例
|
|
func (e *Error) WithStatus(status int) *Error {
|
|
if e.status != status {
|
|
c := *e
|
|
c.status = status
|
|
return &c
|
|
}
|
|
return e
|
|
}
|
|
|
|
// WithText 通过新的错误提示派生新的实例
|
|
func (e *Error) WithText(text string) *Error {
|
|
if text != e.text {
|
|
c := *e
|
|
c.text = text
|
|
return &c
|
|
}
|
|
return e
|
|
}
|
|
|
|
// WithData 通过携带数据派生新的实例
|
|
func (e *Error) WithData(data any) *Error {
|
|
if e.data != data {
|
|
c := *e
|
|
c.data = data
|
|
return &c
|
|
}
|
|
return e
|
|
}
|
|
|
|
// String 实现 fmt.Stringer 接口
|
|
func (e *Error) String() string {
|
|
return strings.TrimSpace(fmt.Sprintf("%d %s", e.code, e.text))
|
|
}
|
|
|
|
// Error 实现错误接口
|
|
func (e *Error) Error() string {
|
|
return e.String()
|
|
}
|
|
|