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