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.
135 lines
3.8 KiB
135 lines
3.8 KiB
package rsp
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/labstack/echo/v4"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
// ErrOK 表示没有任何错误。
|
|
// 对应 HTTP 响应状态码为 500。
|
|
ErrOK = NewError(0, "")
|
|
|
|
// ErrInternal 客户端请求有效,但服务器处理时发生了意外。
|
|
// 对应 HTTP 响应状态码为 500。
|
|
ErrInternal = NewError(-100, "系统内部错误")
|
|
|
|
// ErrServiceUnavailable 服务器无法处理请求,一般用于网站维护状态。
|
|
// 对应 HTTP 响应状态码为 503。
|
|
ErrServiceUnavailable = NewError(-101, "Service Unavailable")
|
|
|
|
// ErrUnauthorized 用户未提供身份验证凭据,或者没有通过身份验证。
|
|
// 响应的 HTTP 状态码为 401。
|
|
ErrUnauthorized = NewError(-102, "unauthorized")
|
|
|
|
// ErrForbidden 用户通过了身份验证,但是不具有访问资源所需的权限。
|
|
// 响应的 HTTP 状态码为 403。
|
|
ErrForbidden = NewError(-103, "Forbidden")
|
|
|
|
// ErrGone 所请求的资源已从这个地址转移,不再可用。
|
|
// 响应的 HTTP 状态码为 410。
|
|
ErrGone = NewError(-104, "Gone")
|
|
|
|
// ErrUnsupportedMediaType 客户端要求的返回格式不支持。
|
|
// 比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式。
|
|
// 响应的 HTTP 状态码为 415。
|
|
ErrUnsupportedMediaType = NewError(-105, "Unsupported Media Type")
|
|
|
|
// ErrUnprocessableEntity 无法处理客户端上传的附件,导致请求失败。
|
|
// 响应的 HTTP 状态码为 422。
|
|
ErrUnprocessableEntity = NewError(-106, "Unprocessable Entity")
|
|
|
|
// ErrTooManyRequests 客户端的请求次数超过限额。
|
|
// 响应的 HTTP 状态码为 422。
|
|
ErrTooManyRequests = NewError(-107, "Too Many Requests")
|
|
|
|
// ErrSeeOther 表示需要参考另一个 URL 才能完成接收的请求操作,
|
|
// 当请求方式使用 POST、PUT 和 DELETE 时,对应的 HTTP 状态码为 303,
|
|
// 其它的请求方式在大多数情况下应该使用 400 状态码。
|
|
ErrSeeOther = NewError(-108, "see other")
|
|
|
|
// ErrBadRequest 服务器不理解客户端的请求。
|
|
// 对应 HTTP 状态码为 404。
|
|
ErrBadRequest = NewError(-109, "bad request")
|
|
|
|
// ErrBadParams 客户端提交的参数不符合要求
|
|
// 对应 HTTP 状态码为 400。
|
|
ErrBadParams = NewError(-110, "参数错误")
|
|
|
|
// ErrRecordNotFound 访问的数据不存在
|
|
// 对应 HTTP 状态码为 404。
|
|
ErrRecordNotFound = NewError(-111, "record not found")
|
|
)
|
|
|
|
type Error struct {
|
|
code int
|
|
text string
|
|
}
|
|
|
|
func NewError(code int, text string) *Error {
|
|
return &Error{code, text}
|
|
}
|
|
|
|
func (e *Error) Code() int {
|
|
return e.code
|
|
}
|
|
|
|
func (e *Error) Text() string {
|
|
return e.text
|
|
}
|
|
|
|
func (e *Error) WithText(text ...string) *Error {
|
|
for _, s := range text {
|
|
if s != "" {
|
|
return NewError(e.code, s)
|
|
}
|
|
}
|
|
return e
|
|
}
|
|
|
|
func (e *Error) AsProblem(label string) *Problem {
|
|
return &Problem{
|
|
Label: label,
|
|
Code: e.code,
|
|
Message: e.text,
|
|
Problems: nil,
|
|
}
|
|
}
|
|
|
|
func (e *Error) AsHttpError(code int) *echo.HTTPError {
|
|
he := echo.NewHTTPError(code, e.text)
|
|
return he.WithInternal(e)
|
|
}
|
|
|
|
func (e *Error) String() string {
|
|
return strings.TrimSpace(fmt.Sprintf("%d %s", e.code, e.text))
|
|
}
|
|
|
|
func (e *Error) Error() string {
|
|
return e.String()
|
|
}
|
|
|
|
type Problem struct {
|
|
Label string `json:"-" xml:"-"`
|
|
Code int `json:"code" xml:"code"`
|
|
Message string `json:"message" xml:"message"`
|
|
Problems map[string][]*Problem `json:"problems,omitempty" xml:"errors,omitempty"`
|
|
}
|
|
|
|
func (p *Problem) AddSubproblem(err *Problem) {
|
|
if p.Problems == nil {
|
|
p.Problems = make(map[string][]*Problem)
|
|
}
|
|
if _, ok := p.Problems[err.Label]; !ok {
|
|
p.Problems[err.Label] = make([]*Problem, 0)
|
|
}
|
|
p.Problems[err.Label] = append(p.Problems[err.Label], err)
|
|
}
|
|
|
|
func (p *Problem) Error() string {
|
|
return fmt.Sprintf(
|
|
"label=%s code=%d, message=%v",
|
|
p.Label, p.Code, p.Message,
|
|
)
|
|
}
|
|
|