github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/courier/status_error/status_error.go (about) 1 package status_error 2 3 import ( 4 "bytes" 5 "fmt" 6 "regexp" 7 "sort" 8 "strconv" 9 ) 10 11 // code, key, msg, desc, canBeTalkError 12 var RegexpStatusError = regexp.MustCompile(`@httpError\(([0-9]+),(.+),"(.+)?","(.+)?",(false|true)\);`) 13 14 func ParseString(s string) *StatusError { 15 matched := RegexpStatusError.FindStringSubmatch(s) 16 if len(matched) != 6 { 17 return nil 18 } 19 20 code, _ := strconv.ParseInt(matched[1], 10, 64) 21 canBeTalkErr, _ := strconv.ParseBool(matched[5]) 22 23 return &StatusError{ 24 Code: code, 25 Key: matched[2], 26 Msg: matched[3], 27 Desc: matched[4], 28 CanBeErrorTalk: canBeTalkErr, 29 } 30 } 31 32 func FromError(err error) *StatusError { 33 if err == nil { 34 return nil 35 } 36 37 if statusErrCode, ok := err.(StatusErrorCode); ok { 38 return statusErrCode.StatusError() 39 } 40 41 if statusError, ok := err.(*StatusError); ok { 42 return statusError 43 } 44 45 return UnknownError.StatusError().WithDesc(err.Error()) 46 } 47 48 func (statusErr *StatusError) String() string { 49 return fmt.Sprintf(`@httpError(%d,%s,"%s","%s",%v);`, statusErr.Code, statusErr.Key, statusErr.Msg, statusErr.Desc, statusErr.CanBeErrorTalk) 50 } 51 52 type StatusError struct { 53 // 错误 Key 54 Key string `json:"key" xml:"key"` 55 // 错误代码 56 Code int64 `json:"code" xml:"code"` 57 // 错误信息 58 Msg string `json:"msg" xml:"msg"` 59 // 详细描述 60 Desc string `json:"desc" xml:"desc"` 61 // 是否能作为错误话术 62 CanBeErrorTalk bool `json:"canBeTalkError" xml:"canBeTalkError"` 63 // 错误溯源 64 Source []string `json:"source" xml:"source"` 65 // 请求 ID 66 ID string `json:"id" xml:"id"` 67 // 出错字段 68 ErrorFields ErrorFields `json:"errorFields" xml:"errorFields"` 69 } 70 71 func (statusErr *StatusError) Is(err error) bool { 72 return FromError(statusErr).Code == statusErr.Code 73 } 74 75 func (statusErr *StatusError) Error() string { 76 return fmt.Sprintf("%v[%s][%d][%s%s] %s", statusErr.Source, statusErr.Key, statusErr.Code, statusErr.Msg, statusErr.ErrorFields, statusErr.Desc) 77 } 78 79 func (statusErr *StatusError) Status() int { 80 strCode := fmt.Sprintf("%d", statusErr.Code) 81 if len(strCode) < 3 { 82 return 0 83 } 84 status, _ := strconv.Atoi(strCode[:3]) 85 return status 86 } 87 88 // deprecated 89 func (statusErr *StatusError) HttpCode() int { 90 return statusErr.Status() 91 } 92 93 func (statusErr StatusError) WithErrTalk() *StatusError { 94 statusErr.CanBeErrorTalk = true 95 return &statusErr 96 } 97 98 func (statusErr StatusError) WithMsg(msg string) *StatusError { 99 statusErr.Msg = msg 100 return &statusErr 101 } 102 103 func (statusErr StatusError) WithoutErrTalk() *StatusError { 104 statusErr.CanBeErrorTalk = false 105 return &statusErr 106 } 107 108 func (statusErr StatusError) WithDesc(desc string) *StatusError { 109 statusErr.Desc = desc 110 return &statusErr 111 } 112 113 func (statusErr StatusError) WithID(id string) *StatusError { 114 statusErr.ID = id 115 return &statusErr 116 } 117 118 func (statusErr StatusError) WithSource(sourceName string) *StatusError { 119 length := len(statusErr.Source) 120 if length == 0 || statusErr.Source[length-1] != sourceName { 121 statusErr.Source = append(statusErr.Source, sourceName) 122 } 123 return &statusErr 124 } 125 126 func (statusErr StatusError) WithErrorField(in string, field string, msg string) *StatusError { 127 statusErr.ErrorFields = append(statusErr.ErrorFields, NewErrorField(in, field, msg)) 128 return &statusErr 129 } 130 131 func (statusErr StatusError) WithErrorFields(errorFields ...*ErrorField) *StatusError { 132 statusErr.ErrorFields = append(statusErr.ErrorFields, errorFields...) 133 return &statusErr 134 } 135 136 func NewErrorField(in string, field string, msg string) *ErrorField { 137 return &ErrorField{ 138 In: in, 139 Field: field, 140 Msg: msg, 141 } 142 } 143 144 type ErrorField struct { 145 // 出错字段路径 146 // 这个信息为一个 json 字符串,方便客户端进行定位错误原因 147 // 例如输入中 {"name":{ "alias" : "test"}} 中的alias出错,则返回 "name.alias" 148 // 如果alias是数组, 且第2个元素的a字段错误,则返回"name.alias[2].a" 149 Field string `json:"field" xml:"field"` 150 // 错误信息 151 Msg string `json:"msg" xml:"msg"` 152 // 错误字段位置 153 // body, query, header, path, formData 154 In string `json:"in" xml:"in"` 155 } 156 157 func (s ErrorField) String() string { 158 return "[" + s.In + "]" + s.Field + " " + s.Msg 159 } 160 161 type ErrorFields []*ErrorField 162 163 func (fields ErrorFields) String() string { 164 if len(fields) == 0 { 165 return "" 166 } 167 buf := &bytes.Buffer{} 168 buf.WriteString("<") 169 for _, f := range fields { 170 buf.WriteString(f.String()) 171 } 172 buf.WriteString(">") 173 return buf.String() 174 } 175 176 func (fields ErrorFields) Sort() ErrorFields { 177 sort.Sort(fields) 178 return fields 179 } 180 181 func (fields ErrorFields) Len() int { 182 return len(fields) 183 } 184 func (fields ErrorFields) Swap(i, j int) { 185 fields[i], fields[j] = fields[j], fields[i] 186 } 187 func (fields ErrorFields) Less(i, j int) bool { 188 return fields[i].Field < fields[j].Field 189 }