fix: recode error handling to make conform with error handling standard

This commit is contained in:
Qiu Jian
2019-11-11 02:06:24 +08:00
parent cf4bb0e642
commit 53c0d3b29f
8 changed files with 401 additions and 208 deletions
+1 -1
View File
@@ -112,7 +112,7 @@ func newInvalidStructError(key string, err error) error {
params := []interface{}{key}
jsonClientErr, ok := err.(*httputils.JSONClientError)
if ok {
errFmt += httperrors.MsgTmplToFmt(jsonClientErr.Data.Id)
errFmt += httputils.MsgTmplToFmt(jsonClientErr.Data.Id)
for _, f := range jsonClientErr.Data.Fields {
params = append(params, f)
}
+11 -11
View File
@@ -16,6 +16,8 @@ package cloudprovider
import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/httperrors"
)
const (
@@ -27,15 +29,13 @@ const (
CloudVMStatusDeploying = "deploying"
CloudVMStatusOther = "other"
ErrUnauthenticated = errors.Error("not authenticated")
ErrUnauthorized = errors.Error("not authorized")
ErrNotFound = errors.Error("id not found")
ErrDuplicateId = errors.Error("duplicate id")
ErrInvalidStatus = errors.Error("invalid status")
ErrTimeout = errors.Error("timeout")
ErrNotImplemented = errors.Error("Not implemented")
ErrNotSupported = errors.Error("Not supported")
ErrInvalidProvider = errors.Error("Invalid provider")
ErrNoBalancePermission = errors.Error("No balance permission")
ErrBadRequest = errors.Error("bad request")
ErrNotFound = errors.ErrNotFound
ErrDuplicateId = errors.ErrDuplicateId
ErrInvalidStatus = errors.ErrInvalidStatus
ErrTimeout = errors.ErrTimeout
ErrNotImplemented = errors.ErrNotImplemented
ErrNotSupported = errors.ErrNotSupported
ErrInvalidProvider = httperrors.ErrInvalidProvider
ErrNoBalancePermission = httperrors.ErrNoBalancePermission
)
+130 -12
View File
@@ -19,16 +19,134 @@ import (
)
const (
ErrUnauthenticated = errors.Error("not authenticated")
ErrUnauthorized = errors.Error("not authorized")
ErrNotFound = errors.Error("id not found")
ErrDuplicateId = errors.Error("duplicate id")
ErrInvalidStatus = errors.Error("invalid status")
ErrTimeout = errors.Error("timeout")
ErrNotImplemented = errors.Error("Not implemented")
ErrNotSupported = errors.Error("Not supported")
ErrBadRequest = errors.Error("bad request")
ErrOutOfRange = errors.Error("out of range")
ErrForbidden = errors.Error("not allowed")
ErrOutOfLimit = errors.Error("out of limit")
ErrBadGateway = errors.Error("BadGateway")
ErrNotImplemented = errors.ErrNotImplemented
ErrInternalError = errors.Error("InternalServerError")
ErrResourceNotReady = errors.Error("ResourceNotReadyError")
ErrPayment = errors.Error("PaymentError")
ErrImageNotFound = errors.Error("ImageNotFoundError")
ErrResourceNotFound = errors.Error("ResourceNotFoundError")
ErrSpecNotFound = errors.Error("SpecNotFoundError")
ErrActionNotFound = errors.Error("ActionNotFoundError")
ErrTenantNotFound = errors.Error("TenantNotFoundError")
ErrUserNotFound = errors.Error("UserNotFoundError")
ErrServerStatus = errors.Error("ServerStatusError")
ErrInvalidStatus = errors.ErrInvalidStatus
ErrInputParameter = errors.Error("InputParameterError")
ErrWeakPassword = errors.Error("WeakPasswordError")
ErrMissingParameter = errors.Error("MissingParameterError")
ErrInsufficientResource = errors.Error("InsufficientResourceError")
ErrOutOfResource = errors.Error("OutOfResource")
ErrOutOfQuota = errors.Error("OutOfQuotaError")
ErrOutOfRange = errors.Error("OutOfRange")
ErrOutOfLimit = errors.Error("OutOfLimit")
ErrNotSufficientPrivilege = errors.Error("NotSufficientPrivilegeError")
ErrUnsupportedOperation = errors.Error("UnsupportOperationError")
ErrNotSupported = errors.ErrNotSupported
ErrNotEmpty = errors.Error("NotEmptyError")
ErrBadRequest = errors.Error("BadRequestError")
ErrUnauthorized = errors.Error("UnauthorizedError")
ErrInvalidCredential = errors.Error("InvalidCredentialError")
ErrUnauthenticated = ErrInvalidCredential
ErrForbidden = errors.Error("ForbiddenError")
ErrNotFound = errors.ErrNotFound
ErrNotAcceptable = errors.Error("NotAcceptableError")
ErrDuplicateName = errors.Error("DuplicateNameError")
ErrDuplicateResource = errors.Error("DuplicateResourceError")
ErrConflict = errors.Error("ConflictError")
ErrDuplicateId = errors.ErrDuplicateId
ErrResourceBusy = errors.Error("ResourceBusyError")
ErrRequireLicense = errors.Error("RequireLicenseError")
ErrTimeout = errors.ErrTimeout
ErrProtectedResource = errors.Error("ProtectedResourceError")
ErrNoProject = errors.Error("NoProjectError")
ErrInvalidProvider = errors.Error("InvalidProvider")
ErrNoBalancePermission = errors.Error("NoBalancePermission")
)
var (
httpErrorCode = map[errors.Error]int{
errors.ErrClient: 400,
errors.ErrServer: 500,
errors.ErrUnclassified: 500,
ErrInvalidProvider: 400,
ErrNoBalancePermission: 403,
ErrBadGateway: 502,
ErrNotImplemented: 501,
ErrInternalError: 500,
ErrResourceNotReady: 500,
ErrPayment: 402,
ErrImageNotFound: 404,
ErrResourceNotFound: 404,
ErrSpecNotFound: 404,
ErrActionNotFound: 404,
ErrTenantNotFound: 404,
ErrUserNotFound: 404,
ErrServerStatus: 400,
ErrInvalidStatus: 400,
ErrInputParameter: 400,
ErrWeakPassword: 400,
ErrMissingParameter: 400,
ErrInsufficientResource: 400,
ErrOutOfResource: 500,
ErrOutOfQuota: 400,
ErrOutOfRange: 400,
ErrOutOfLimit: 400,
ErrNotSufficientPrivilege: 403,
ErrUnsupportedOperation: 406,
ErrNotSupported: 406,
ErrNotEmpty: 406,
ErrBadRequest: 400,
ErrUnauthorized: 401,
ErrInvalidCredential: 401,
ErrForbidden: 403,
ErrNotFound: 404,
ErrNotAcceptable: 406,
ErrDuplicateName: 409,
ErrDuplicateResource: 409,
ErrConflict: 409,
ErrDuplicateId: 409,
ErrResourceBusy: 409,
ErrRequireLicense: 402,
ErrTimeout: 504,
ErrProtectedResource: 403,
ErrNoProject: 403,
}
)
func RegisterErrorHttpCode(err errors.Error, code int) {
if _, ok := httpErrorCode[err]; ok {
panic("Error has been registered: " + string(err))
}
httpErrorCode[err] = code
}
+69 -184
View File
@@ -15,156 +15,45 @@
package httperrors
import (
"bytes"
"fmt"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/util/httputils"
)
func NewJsonClientError(code int, title string, msg string, error httputils.Error) *httputils.JSONClientError {
err := httputils.JSONClientError{Code: code, Class: title, Details: msg, Data: error}
return &err
}
func msgFmtToTmpl(msgFmt string) string {
// 将%s %d之类格式化字符串转换成{0}、{1}格式
// 注意: 1.不支持复杂类型的转换例如%.2f , %[1]d, % x
// 2.原始msgFmt中如果包含{0},{1}形式的字符串同样会引发错误。
// 在抛出error msgFmt时应注意避免
fmtstr := false
lst := []rune(msgFmt)
lastIndex := len(lst) - 1
temp := bytes.Buffer{}
index := 0
for i, c := range lst {
switch c {
case '%':
if fmtstr || i == lastIndex {
temp.WriteRune(c)
fmtstr = false
} else {
fmtstr = true
}
case 'v', 'T', 't', 'b', 'c', 'd', 'o', 'q', 'x', 'X', 'U', 'e', 'E', 'f', 'F', 'g', 'G', 's', 'p':
if fmtstr {
temp.WriteRune('{')
temp.WriteString(fmt.Sprintf("%d", index))
temp.WriteRune('}')
index++
fmtstr = false
} else {
temp.WriteRune(c)
}
default:
if fmtstr {
temp.WriteRune('%')
}
temp.WriteRune(c)
fmtstr = false
}
}
return temp.String()
}
func MsgTmplToFmt(tmpl string) string {
return msgTmplToFmt(tmpl)
}
func msgTmplToFmt(tmpl string) string {
b := &bytes.Buffer{}
for i := 0; i < len(tmpl); {
r := tmpl[i]
if r != '{' {
b.WriteByte(r)
i++
continue
}
j := i + 1
for ; j < len(tmpl); j++ {
r := tmpl[j]
if r < '0' || r > '9' {
break
}
}
if j == len(tmpl) {
b.WriteString(tmpl[i:])
return b.String()
}
if j > i+1 && tmpl[j] == '}' {
b.WriteString("%s")
i = j + 1
} else {
b.WriteString(tmpl[i:j])
i = j
}
}
return b.String()
}
func errorMessage(msgFmt string, params ...interface{}) (string, httputils.Error) {
fields := make([]string, len(params))
for i, v := range params {
fields[i] = fmt.Sprint(v)
}
err := httputils.Error{
Id: msgFmtToTmpl(msgFmt),
Fields: fields,
}
msg := msgFmt
if len(params) > 0 {
msg = fmt.Sprintf(msg, params...)
}
return msg, err
}
func NewBadGatewayError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(502, "BadGateway", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrBadGateway], string(ErrBadGateway), msg, params...)
}
func NewNotImplementedError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(501, "NotImplemented", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrNotImplemented], string(ErrNotImplemented), msg, params...)
}
func NewInternalServerError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(500, "InternalServerError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrInternalError], string(ErrInternalError), msg, params...)
}
func NewResourceNotReadyError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(500, "ResourceNotReadyError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrResourceNotReady], string(ErrResourceNotReady), msg, params...)
}
func NewOutOfResourceError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(500, "NewOutOfResourceError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrOutOfResource], string(ErrOutOfResource), msg, params...)
}
func NewServerStatusError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(400, "ServerStatusError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrServerStatus], string(ErrServerStatus), msg, params...)
}
func NewPaymentError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(402, "PaymentError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrPayment], string(ErrPayment), msg, params...)
}
func NewImageNotFoundError(imageId string) *httputils.JSONClientError {
msg, err := errorMessage("Image %s not found", imageId)
return NewJsonClientError(404, "ImageNotFoundError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrImageNotFound], string(ErrImageNotFound), "Image %s not found", imageId)
}
func NewResourceNotFoundError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(404, "ResourceNotFoundError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrResourceNotFound], string(ErrResourceNotFound), msg, params...)
}
func NewResourceNotFoundError2(keyword, id string) *httputils.JSONClientError {
@@ -172,145 +61,141 @@ func NewResourceNotFoundError2(keyword, id string) *httputils.JSONClientError {
}
func NewSpecNotFoundError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(404, "SpecNotFoundError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrSpecNotFound], string(ErrSpecNotFound), msg, params...)
}
func NewActionNotFoundError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(404, "ActionNotFoundError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrActionNotFound], string(ErrActionNotFound), msg, params...)
}
func NewTenantNotFoundError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(404, "TenantNotFoundError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrTenantNotFound], string(ErrTenantNotFound), msg, params...)
}
func NewUserNotFoundError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(404, "UserNotFoundError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrUserNotFound], string(ErrUserNotFound), msg, params...)
}
func NewInvalidStatusError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(400, "InvalidStatusError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrInvalidStatus], string(ErrInvalidStatus), msg, params...)
}
func NewInputParameterError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(400, "InputParameterError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrInputParameter], string(ErrInputParameter), msg, params...)
}
func NewWeakPasswordError() *httputils.JSONClientError {
msg, err := errorMessage("password must be 12 chars of at least one digit, letter, uppercase letter and punctuate")
return NewJsonClientError(400, "WeakPasswordError", msg, err)
msg := ("password must be 12 chars of at least one digit, letter, uppercase letter and punctuate")
return httputils.NewJsonClientError(httpErrorCode[ErrWeakPassword], string(ErrWeakPassword), msg)
}
func NewMissingParameterError(paramName string) *httputils.JSONClientError {
msg, err := errorMessage("Missing parameter %s", paramName)
return NewJsonClientError(400, "MissingParameterError", msg, err)
msg := "Missing parameter %s"
return httputils.NewJsonClientError(httpErrorCode[ErrMissingParameter], string(ErrMissingParameter), msg, paramName)
}
func NewInsufficientResourceError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(400, "InsufficientResourceError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrInsufficientResource], string(ErrInsufficientResource), msg, params...)
}
func NewOutOfQuotaError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(400, "OutOfQuotaError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrOutOfQuota], string(ErrOutOfQuota), msg, params...)
}
func NewOutOfRangeError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[ErrOutOfRange], string(ErrOutOfRange), msg, params...)
}
func NewOutOfLimitError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[ErrOutOfLimit], string(ErrOutOfLimit), msg, params...)
}
func NewNotSufficientPrivilegeError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(403, "NotSufficientPrivilegeError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrNotSufficientPrivilege], string(ErrNotSufficientPrivilege), msg, params...)
}
func NewUnsupportOperationError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(406, "UnsupportOperationError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrUnsupportedOperation], string(ErrUnsupportedOperation), msg, params...)
}
func NewNotSupportedError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[ErrNotSupported], string(ErrNotSupported), msg, params...)
}
func NewNotEmptyError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(406, "NotEmptyError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrNotEmpty], string(ErrNotEmpty), msg, params...)
}
func NewBadRequestError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(400, "BadRequestError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrBadRequest], string(ErrBadRequest), msg, params...)
}
func NewUnauthorizedError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(401, "UnauthorizedError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrUnauthorized], string(ErrUnauthorized), msg, params...)
}
func NewInvalidCredentialError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(401, "InvalidCredentialError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrInvalidCredential], string(ErrInvalidCredential), msg, params...)
}
func NewForbiddenError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(403, "ForbiddenError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrForbidden], string(ErrForbidden), msg, params...)
}
func NewNotFoundError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(404, "NotFoundError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrNotFound], string(ErrNotFound), msg, params...)
}
func NewNotAcceptableError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(406, "NotAcceptableError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrNotAcceptable], string(ErrNotAcceptable), msg, params...)
}
func NewDuplicateNameError(resName string, resId string) *httputils.JSONClientError {
msg, err := errorMessage("Duplicate %s %s", resName, resId)
return NewJsonClientError(409, "DuplicateNameError", msg, err)
msg := "Duplicate name %s %s"
return httputils.NewJsonClientError(httpErrorCode[ErrDuplicateName], string(ErrDuplicateName), msg, resName, resId)
}
func NewDuplicateIdError(resName string, resId string) *httputils.JSONClientError {
msg := "Duplicate ID %s %s"
return httputils.NewJsonClientError(httpErrorCode[ErrDuplicateId], string(ErrDuplicateId), msg, resName, resId)
}
func NewDuplicateResourceError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params)
return NewJsonClientError(409, "DuplicateResourceError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrDuplicateResource], string(ErrDuplicateResource), msg, params...)
}
func NewConflictError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(409, "ConflictError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrConflict], string(ErrConflict), msg, params...)
}
func NewResourceBusyError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(409, "ResourceBusyError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrResourceBusy], string(ErrResourceBusy), msg, params...)
}
func NewRequireLicenseError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(402, "RequireLicenseError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrRequireLicense], string(ErrRequireLicense), msg, params...)
}
func NewTimeoutError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(504, "TimeoutError", msg, err)
}
func NewGeneralError(err error) *httputils.JSONClientError {
switch err.(type) {
case *httputils.JSONClientError:
return err.(*httputils.JSONClientError)
default:
return NewInternalServerError(err.Error())
}
return httputils.NewJsonClientError(httpErrorCode[ErrTimeout], string(ErrTimeout), msg, params...)
}
func NewProtectedResourceError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(403, "ProtectedResourceError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrProtectedResource], string(ErrProtectedResource), msg, params...)
}
func NewNoProjectError(msg string, params ...interface{}) *httputils.JSONClientError {
msg, err := errorMessage(msg, params...)
return NewJsonClientError(403, "NoProjectError", msg, err)
return httputils.NewJsonClientError(httpErrorCode[ErrNoProject], string(ErrNoProject), msg, params...)
}
func NewServerError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[errors.ErrServer], string(errors.ErrServer), msg, params...)
}
func NewClientError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[errors.ErrClient], string(errors.ErrClient), msg, params...)
}
func NewUnclassifiedError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[errors.ErrUnclassified], string(errors.ErrUnclassified), msg, params)
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package httperrors
import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/util/httputils"
)
func NewGeneralError(err error) *httputils.JSONClientError {
switch nerr := err.(type) {
case *httputils.JSONClientError:
return nerr
case errors.Error:
code, ok := httpErrorCode[nerr]
if !ok {
code = 500
}
return httputils.NewJsonClientError(code, string(nerr), err.Error())
default:
root := errors.Cause(err)
switch nerr := root.(type) {
case *httputils.JSONClientError:
nerr.Details = err.Error()
return nerr
case errors.Error:
code, ok := httpErrorCode[nerr]
if !ok {
code = 500
}
return httputils.NewJsonClientError(code, string(nerr), err.Error())
default:
return NewUnclassifiedError(err.Error())
}
}
}
+112
View File
@@ -0,0 +1,112 @@
package httputils
import (
"bytes"
"fmt"
)
// New a http Json client error
// code: http error code, >=400
// class: error class
// msg: message
// params: message format parameters
func NewJsonClientError(code int, class string, msg string, params ...interface{}) *JSONClientError {
details, err := errorMessage(msg, params...)
return &JSONClientError{Code: code, Class: class, Details: details, Data: err}
}
func errorMessage(msgFmt string, params ...interface{}) (string, Error) {
fields := make([]string, len(params))
for i, v := range params {
fields[i] = fmt.Sprint(v)
}
err := Error{
Id: msgFmtToTmpl(msgFmt),
Fields: fields,
}
msg := msgFmt
if len(params) > 0 {
msg = fmt.Sprintf(msg, params...)
}
return msg, err
}
func msgFmtToTmpl(msgFmt string) string {
// 将%s %d之类格式化字符串转换成{0}、{1}格式
// 注意: 1.不支持复杂类型的转换例如%.2f , %[1]d, % x
// 2.原始msgFmt中如果包含{0},{1}形式的字符串同样会引发错误。
// 在抛出error msgFmt时应注意避免
fmtstr := false
lst := []rune(msgFmt)
lastIndex := len(lst) - 1
temp := bytes.Buffer{}
index := 0
for i, c := range lst {
switch c {
case '%':
if fmtstr || i == lastIndex {
temp.WriteRune(c)
fmtstr = false
} else {
fmtstr = true
}
case 'v', 'T', 't', 'b', 'c', 'd', 'o', 'q', 'x', 'X', 'U', 'e', 'E', 'f', 'F', 'g', 'G', 's', 'p':
if fmtstr {
temp.WriteRune('{')
temp.WriteString(fmt.Sprintf("%d", index))
temp.WriteRune('}')
index++
fmtstr = false
} else {
temp.WriteRune(c)
}
default:
if fmtstr {
temp.WriteRune('%')
}
temp.WriteRune(c)
fmtstr = false
}
}
return temp.String()
}
func MsgTmplToFmt(tmpl string) string {
return msgTmplToFmt(tmpl)
}
func msgTmplToFmt(tmpl string) string {
b := &bytes.Buffer{}
for i := 0; i < len(tmpl); {
r := tmpl[i]
if r != '{' {
b.WriteByte(r)
i++
continue
}
j := i + 1
for ; j < len(tmpl); j++ {
r := tmpl[j]
if r < '0' || r > '9' {
break
}
}
if j == len(tmpl) {
b.WriteString(tmpl[i:])
return b.String()
}
if j > i+1 && tmpl[j] == '}' {
b.WriteString("%s")
i = j + 1
} else {
b.WriteString(tmpl[i:j])
i = j
}
}
return b.String()
}
+13
View File
@@ -33,6 +33,7 @@ import (
"github.com/moul/http2curl"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/pkg/trace"
@@ -81,6 +82,18 @@ func (e *JSONClientError) Error() string {
return jsonutils.Marshal(errMsg).String()
}
func (err *JSONClientError) Cause() error {
if len(err.Class) > 0 {
return errors.Error(err.Class)
} else if err.Code >= 500 {
return errors.ErrServer
} else if err.Code >= 400 {
return errors.ErrClient
} else {
return errors.ErrUnclassified
}
}
func ErrorCode(err error) int {
if err == nil {
return 0
+16
View File
@@ -22,6 +22,7 @@ import (
"testing"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
)
type SErrorMsg struct {
@@ -125,3 +126,18 @@ func TestError(t *testing.T) {
}
}
func TestErrorCause(t *testing.T) {
err := errors.Error("TestError")
jsonError := &JSONClientError{
Code: 400,
Class: string(err),
Details: "detailed test error",
}
wrapError := errors.Wrap(jsonError, "wrap1")
if errors.Cause(wrapError) == err {
t.Logf("%s", wrapError)
} else {
t.Errorf("wrapErro.Cause should be err: %#v != %#v", errors.Cause(wrapError), err)
}
}