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  }