mirror of
				https://github.com/go-kratos/kratos.git
				synced 2025-10-30 23:47:59 +02:00 
			
		
		
		
	
							
								
								
									
										317
									
								
								errors/codes.go
									
									
									
									
									
								
							
							
						
						
									
										317
									
								
								errors/codes.go
									
									
									
									
									
								
							| @@ -1,317 +0,0 @@ | ||||
| package errors | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| // Cancelled The operation was cancelled, typically by the caller. | ||||
| // HTTP Mapping: 499 Client Closed Request | ||||
| func Cancelled(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    1, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsCancelled determines if err is an error which indicates a cancelled error. | ||||
| // It supports wrapped errors. | ||||
| func IsCancelled(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 1 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Unknown error. | ||||
| // HTTP Mapping: 500 Internal Server Error | ||||
| func Unknown(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    2, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsUnknown determines if err is an error which indicates a unknown error. | ||||
| // It supports wrapped errors. | ||||
| func IsUnknown(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 2 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // InvalidArgument The client specified an invalid argument. | ||||
| // HTTP Mapping: 400 Bad Request | ||||
| func InvalidArgument(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    3, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsInvalidArgument determines if err is an error which indicates an invalid argument error. | ||||
| // It supports wrapped errors. | ||||
| func IsInvalidArgument(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 3 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // DeadlineExceeded The deadline expired before the operation could complete. | ||||
| // HTTP Mapping: 504 Gateway Timeout | ||||
| func DeadlineExceeded(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    4, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsDeadlineExceeded determines if err is an error which indicates a deadline exceeded error. | ||||
| // It supports wrapped errors. | ||||
| func IsDeadlineExceeded(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 4 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // NotFound Some requested entity (e.g., file or directory) was not found. | ||||
| // HTTP Mapping: 404 Not Found | ||||
| func NotFound(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    5, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsNotFound determines if err is an error which indicates a not found error. | ||||
| // It supports wrapped errors. | ||||
| func IsNotFound(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 5 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // AlreadyExists The entity that a client attempted to create (e.g., file or directory) already exists. | ||||
| // HTTP Mapping: 409 Conflict | ||||
| func AlreadyExists(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    6, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsAlreadyExists determines if err is an error which indicates a already exsits error. | ||||
| // It supports wrapped errors. | ||||
| func IsAlreadyExists(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 6 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // PermissionDenied The caller does not have permission to execute the specified operation. | ||||
| // HTTP Mapping: 403 Forbidden | ||||
| func PermissionDenied(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    7, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsPermissionDenied determines if err is an error which indicates a permission denied error. | ||||
| // It supports wrapped errors. | ||||
| func IsPermissionDenied(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 7 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // ResourceExhausted Some resource has been exhausted, perhaps a per-user quota, or | ||||
| // perhaps the entire file system is out of space. | ||||
| // HTTP Mapping: 429 Too Many Requests | ||||
| func ResourceExhausted(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    8, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsResourceExhausted determines if err is an error which indicates a resource exhausted error. | ||||
| // It supports wrapped errors. | ||||
| func IsResourceExhausted(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 8 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // FailedPrecondition The operation was rejected because the system is not in a state | ||||
| // required for the operation's execution. | ||||
| // HTTP Mapping: 400 Bad Request | ||||
| func FailedPrecondition(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    9, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsFailedPrecondition determines if err is an error which indicates a failed precondition error. | ||||
| // It supports wrapped errors. | ||||
| func IsFailedPrecondition(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 9 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Aborted The operation was aborted, typically due to a concurrency issue such as | ||||
| // a sequencer check failure or transaction abort. | ||||
| // HTTP Mapping: 409 Conflict | ||||
| func Aborted(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    10, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsAborted determines if err is an error which indicates an aborted error. | ||||
| // It supports wrapped errors. | ||||
| func IsAborted(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 10 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // OutOfRange The operation was attempted past the valid range.  E.g., seeking or | ||||
| // reading past end-of-file. | ||||
| // HTTP Mapping: 400 Bad Request | ||||
| func OutOfRange(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    11, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsOutOfRange determines if err is an error which indicates a out of range error. | ||||
| // It supports wrapped errors. | ||||
| func IsOutOfRange(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 11 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Unimplemented The operation is not implemented or is not supported/enabled in this service. | ||||
| // HTTP Mapping: 501 Not Implemented | ||||
| func Unimplemented(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    12, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsUnimplemented determines if err is an error which indicates a unimplemented error. | ||||
| // It supports wrapped errors. | ||||
| func IsUnimplemented(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 12 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Internal This means that some invariants expected by the | ||||
| // underlying system have been broken.  This error code is reserved | ||||
| // for serious errors. | ||||
| // | ||||
| // HTTP Mapping: 500 Internal Server Error | ||||
| func Internal(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    13, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsInternal determines if err is an error which indicates an internal server error. | ||||
| // It supports wrapped errors. | ||||
| func IsInternal(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 13 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Unavailable The service is currently unavailable. | ||||
| // HTTP Mapping: 503 Service Unavailable | ||||
| func Unavailable(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    14, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsUnavailable determines if err is an error which indicates a unavailable error. | ||||
| // It supports wrapped errors. | ||||
| func IsUnavailable(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 14 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // DataLoss Unrecoverable data loss or corruption. | ||||
| // HTTP Mapping: 500 Internal Server Error | ||||
| func DataLoss(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    15, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsDataLoss determines if err is an error which indicates a data loss error. | ||||
| // It supports wrapped errors. | ||||
| func IsDataLoss(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 15 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Unauthorized The request does not have valid authentication credentials for the operation. | ||||
| // HTTP Mapping: 401 Unauthorized | ||||
| func Unauthorized(reason, format string, a ...interface{}) error { | ||||
| 	return &StatusError{ | ||||
| 		Code:    16, | ||||
| 		Reason:  reason, | ||||
| 		Message: fmt.Sprintf(format, a...), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsUnauthorized determines if err is an error which indicates a unauthorized error. | ||||
| // It supports wrapped errors. | ||||
| func IsUnauthorized(err error) bool { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code == 16 | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
							
								
								
									
										125
									
								
								errors/errors.go
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								errors/errors.go
									
									
									
									
									
								
							| @@ -7,110 +7,83 @@ import ( | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// UnknownReason is unknown reason for error info. | ||||
| 	UnknownReason = "" | ||||
| 	// SupportPackageIsVersion1 this constant should not be referenced by any other code. | ||||
| 	SupportPackageIsVersion1 = true | ||||
| ) | ||||
|  | ||||
| var _ error = (*StatusError)(nil) | ||||
| // Error contains an error response from the server. | ||||
| // For more details see https://github.com/go-kratos/kratos/issues/858. | ||||
| type Error struct { | ||||
| 	Code     int               `json:"code"` | ||||
| 	Domain   string            `json:"domain"` | ||||
| 	Reason   string            `json:"reason"` | ||||
| 	Message  string            `json:"message"` | ||||
| 	Metadata map[string]string `json:"metadata"` | ||||
| } | ||||
|  | ||||
| // StatusError contains an error response from the server. | ||||
| type StatusError = Status | ||||
| // WithMetadata with an MD formed by the mapping of key, value. | ||||
| func (e *Error) WithMetadata(md map[string]string) *Error { | ||||
| 	err := *e | ||||
| 	err.Metadata = md | ||||
| 	return &err | ||||
| } | ||||
|  | ||||
| // Is matches each error in the chain with the target value. | ||||
| func (e *StatusError) Is(target error) bool { | ||||
| 	err, ok := target.(*StatusError) | ||||
| 	if ok { | ||||
| 		return e.Code == err.Code | ||||
| func (e *Error) Is(err error) bool { | ||||
| 	if target := new(Error); errors.As(err, &target) { | ||||
| 		return target.Code == e.Code && target.Reason == e.Reason | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // HTTPStatus returns the Status represented by se. | ||||
| func (e *StatusError) HTTPStatus() int { | ||||
| 	switch e.Code { | ||||
| 	case 0: | ||||
| 		return http.StatusOK | ||||
| 	case 1: | ||||
| 		return http.StatusInternalServerError | ||||
| 	case 2: | ||||
| 		return http.StatusInternalServerError | ||||
| 	case 3: | ||||
| 		return http.StatusBadRequest | ||||
| 	case 4: | ||||
| 		return http.StatusRequestTimeout | ||||
| 	case 5: | ||||
| 		return http.StatusNotFound | ||||
| 	case 6: | ||||
| 		return http.StatusConflict | ||||
| 	case 7: | ||||
| 		return http.StatusForbidden | ||||
| 	case 8: | ||||
| 		return http.StatusTooManyRequests | ||||
| 	case 9: | ||||
| 		return http.StatusPreconditionFailed | ||||
| 	case 10: | ||||
| 		return http.StatusConflict | ||||
| 	case 11: | ||||
| 		return http.StatusBadRequest | ||||
| 	case 12: | ||||
| 		return http.StatusNotImplemented | ||||
| 	case 13: | ||||
| 		return http.StatusInternalServerError | ||||
| 	case 14: | ||||
| 		return http.StatusServiceUnavailable | ||||
| 	case 15: | ||||
| 		return http.StatusInternalServerError | ||||
| 	case 16: | ||||
| 		return http.StatusUnauthorized | ||||
| 	default: | ||||
| 		return http.StatusInternalServerError | ||||
| 	} | ||||
| func (e *Error) Error() string { | ||||
| 	return fmt.Sprintf("error: code = %d domain = %s reason = %s message = %s metadata = %v", e.Code, e.Domain, e.Reason, e.Message, e.Metadata) | ||||
| } | ||||
|  | ||||
| func (e *StatusError) Error() string { | ||||
| 	return fmt.Sprintf("error: code = %d reason = %s message = %s details = %+v", e.Code, e.Reason, e.Message, e.Details) | ||||
| } | ||||
|  | ||||
| // Error returns a Status representing c and msg. | ||||
| func Error(code int32, reason, message string) error { | ||||
| 	return &StatusError{ | ||||
| // New returns an error object for the code, message and error info. | ||||
| func New(code int, reason, message string) *Error { | ||||
| 	return &Error{ | ||||
| 		Code:    code, | ||||
| 		Reason:  reason, | ||||
| 		Message: message, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Errorf returns New(c, fmt.Sprintf(format, a...)). | ||||
| func Errorf(code int32, reason, format string, a ...interface{}) error { | ||||
| 	return Error(code, reason, fmt.Sprintf(format, a...)) | ||||
| } | ||||
|  | ||||
| // Code returns the status code. | ||||
| func Code(err error) int32 { | ||||
| // Code returns the code for a particular error. | ||||
| // It supports wrapped errors. | ||||
| func Code(err error) int { | ||||
| 	if err == nil { | ||||
| 		return 0 // ok | ||||
| 		return http.StatusOK | ||||
| 	} | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Code | ||||
| 	if target := new(Error); errors.As(err, &target) { | ||||
| 		return target.Code | ||||
| 	} | ||||
| 	return 2 // unknown | ||||
| 	return http.StatusInternalServerError | ||||
| } | ||||
|  | ||||
| // Reason returns the status for a particular error. | ||||
| // Domain returns the domain for a particular error. | ||||
| // It supports wrapped errors. | ||||
| func Domain(err error) string { | ||||
| 	if target := new(Error); errors.As(err, &target) { | ||||
| 		return target.Domain | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // Reason returns the reason for a particular error. | ||||
| // It supports wrapped errors. | ||||
| func Reason(err error) string { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se.Reason | ||||
| 	if target := new(Error); errors.As(err, &target) { | ||||
| 		return target.Reason | ||||
| 	} | ||||
| 	return UnknownReason | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // FromError returns status error. | ||||
| func FromError(err error) (*StatusError, bool) { | ||||
| 	if se := new(StatusError); errors.As(err, &se) { | ||||
| 		return se, true | ||||
| // FromError try to convert an error to *Error. | ||||
| // It supports wrapped errors. | ||||
| func FromError(err error) *Error { | ||||
| 	if target := new(Error); errors.As(err, &target) { | ||||
| 		return target | ||||
| 	} | ||||
| 	return nil, false | ||||
| 	return New(http.StatusInternalServerError, "", err.Error()) | ||||
| } | ||||
|   | ||||
| @@ -1,187 +0,0 @@ | ||||
| // Code generated by protoc-gen-go. DO NOT EDIT. | ||||
| // versions: | ||||
| // 	protoc-gen-go v1.25.0 | ||||
| // 	protoc        v3.13.0 | ||||
| // source: errors.proto | ||||
|  | ||||
| package errors | ||||
|  | ||||
| import ( | ||||
| 	proto "github.com/golang/protobuf/proto" | ||||
| 	any "github.com/golang/protobuf/ptypes/any" | ||||
| 	protoreflect "google.golang.org/protobuf/reflect/protoreflect" | ||||
| 	protoimpl "google.golang.org/protobuf/runtime/protoimpl" | ||||
| 	reflect "reflect" | ||||
| 	sync "sync" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// Verify that this generated code is sufficiently up-to-date. | ||||
| 	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) | ||||
| 	// Verify that runtime/protoimpl is sufficiently up-to-date. | ||||
| 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) | ||||
| ) | ||||
|  | ||||
| // This is a compile-time assertion that a sufficiently up-to-date version | ||||
| // of the legacy proto package is being used. | ||||
| const _ = proto.ProtoPackageIsVersion4 | ||||
|  | ||||
| type Status struct { | ||||
| 	state         protoimpl.MessageState | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
|  | ||||
| 	Code    int32      `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` | ||||
| 	Reason  string     `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` | ||||
| 	Message string     `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` | ||||
| 	Details []*any.Any `protobuf:"bytes,4,rep,name=details,proto3" json:"details,omitempty"` | ||||
| } | ||||
|  | ||||
| func (x *Status) Reset() { | ||||
| 	*x = Status{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_errors_proto_msgTypes[0] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (x *Status) String() string { | ||||
| 	return protoimpl.X.MessageStringOf(x) | ||||
| } | ||||
|  | ||||
| func (*Status) ProtoMessage() {} | ||||
|  | ||||
| func (x *Status) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_errors_proto_msgTypes[0] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| 			ms.StoreMessageInfo(mi) | ||||
| 		} | ||||
| 		return ms | ||||
| 	} | ||||
| 	return mi.MessageOf(x) | ||||
| } | ||||
|  | ||||
| // Deprecated: Use Status.ProtoReflect.Descriptor instead. | ||||
| func (*Status) Descriptor() ([]byte, []int) { | ||||
| 	return file_errors_proto_rawDescGZIP(), []int{0} | ||||
| } | ||||
|  | ||||
| func (x *Status) GetCode() int32 { | ||||
| 	if x != nil { | ||||
| 		return x.Code | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (x *Status) GetReason() string { | ||||
| 	if x != nil { | ||||
| 		return x.Reason | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (x *Status) GetMessage() string { | ||||
| 	if x != nil { | ||||
| 		return x.Message | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (x *Status) GetDetails() []*any.Any { | ||||
| 	if x != nil { | ||||
| 		return x.Details | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| var File_errors_proto protoreflect.FileDescriptor | ||||
|  | ||||
| var file_errors_proto_rawDesc = []byte{ | ||||
| 	0x0a, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, | ||||
| 	0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x1a, 0x19, 0x67, | ||||
| 	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, | ||||
| 	0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7e, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, | ||||
| 	0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, | ||||
| 	0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, | ||||
| 	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x18, | ||||
| 	0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, | ||||
| 	0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, | ||||
| 	0x69, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, | ||||
| 	0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, | ||||
| 	0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x62, 0x0a, 0x11, 0x64, 0x65, 0x76, 0x2e, | ||||
| 	0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x42, 0x0b, 0x45, | ||||
| 	0x72, 0x72, 0x6f, 0x72, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, | ||||
| 	0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, | ||||
| 	0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x65, 0x72, 0x72, | ||||
| 	0x6f, 0x72, 0x73, 0x3b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x0c, | ||||
| 	0x4b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, | ||||
| 	0x6f, 0x74, 0x6f, 0x33, | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	file_errors_proto_rawDescOnce sync.Once | ||||
| 	file_errors_proto_rawDescData = file_errors_proto_rawDesc | ||||
| ) | ||||
|  | ||||
| func file_errors_proto_rawDescGZIP() []byte { | ||||
| 	file_errors_proto_rawDescOnce.Do(func() { | ||||
| 		file_errors_proto_rawDescData = protoimpl.X.CompressGZIP(file_errors_proto_rawDescData) | ||||
| 	}) | ||||
| 	return file_errors_proto_rawDescData | ||||
| } | ||||
|  | ||||
| var file_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 1) | ||||
| var file_errors_proto_goTypes = []interface{}{ | ||||
| 	(*Status)(nil),  // 0: kratos.errors.Status | ||||
| 	(*any.Any)(nil), // 1: google.protobuf.Any | ||||
| } | ||||
| var file_errors_proto_depIdxs = []int32{ | ||||
| 	1, // 0: kratos.errors.Status.details:type_name -> google.protobuf.Any | ||||
| 	1, // [1:1] is the sub-list for method output_type | ||||
| 	1, // [1:1] is the sub-list for method input_type | ||||
| 	1, // [1:1] is the sub-list for extension type_name | ||||
| 	1, // [1:1] is the sub-list for extension extendee | ||||
| 	0, // [0:1] is the sub-list for field type_name | ||||
| } | ||||
|  | ||||
| func init() { file_errors_proto_init() } | ||||
| func file_errors_proto_init() { | ||||
| 	if File_errors_proto != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if !protoimpl.UnsafeEnabled { | ||||
| 		file_errors_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*Status); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| 				return &v.sizeCache | ||||
| 			case 2: | ||||
| 				return &v.unknownFields | ||||
| 			default: | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	type x struct{} | ||||
| 	out := protoimpl.TypeBuilder{ | ||||
| 		File: protoimpl.DescBuilder{ | ||||
| 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | ||||
| 			RawDescriptor: file_errors_proto_rawDesc, | ||||
| 			NumEnums:      0, | ||||
| 			NumMessages:   1, | ||||
| 			NumExtensions: 0, | ||||
| 			NumServices:   0, | ||||
| 		}, | ||||
| 		GoTypes:           file_errors_proto_goTypes, | ||||
| 		DependencyIndexes: file_errors_proto_depIdxs, | ||||
| 		MessageInfos:      file_errors_proto_msgTypes, | ||||
| 	}.Build() | ||||
| 	File_errors_proto = out.File | ||||
| 	file_errors_proto_rawDesc = nil | ||||
| 	file_errors_proto_goTypes = nil | ||||
| 	file_errors_proto_depIdxs = nil | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| syntax = "proto3"; | ||||
|  | ||||
| package kratos.errors; | ||||
|  | ||||
| import "google/protobuf/any.proto"; | ||||
|  | ||||
| option cc_enable_arenas = true; | ||||
| option go_package = "github.com/go-kratos/kratos/v2/errors;errors"; | ||||
| option java_multiple_files = true; | ||||
| option java_outer_classname = "ErrorsProto"; | ||||
| option java_package = "com.github.kratos.errors"; | ||||
| option objc_class_prefix = "KratosErrors"; | ||||
|  | ||||
| message Status { | ||||
|   int32 code = 1; | ||||
|   string reason = 2; | ||||
|   string message = 3; | ||||
|   repeated google.protobuf.Any details = 4; | ||||
| } | ||||
| @@ -6,49 +6,45 @@ import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestErrorsMatch(t *testing.T) { | ||||
| 	s := &StatusError{Code: 1} | ||||
| 	st := &StatusError{Code: 2} | ||||
| func TestError(t *testing.T) { | ||||
| 	var ( | ||||
| 		base *Error | ||||
| 	) | ||||
| 	err := New(400, "reason", "message") | ||||
| 	err2 := New(400, "reason", "message") | ||||
| 	err3 := err.WithMetadata(map[string]string{ | ||||
| 		"foo": "bar", | ||||
| 	}) | ||||
| 	werr := fmt.Errorf("wrap %w", err) | ||||
|  | ||||
| 	if errors.Is(s, st) { | ||||
| 		t.Errorf("error is not match: %+v -> %+v", s, st) | ||||
| 	if errors.Is(err, new(Error)) { | ||||
| 		t.Errorf("should not be equal: %v", err) | ||||
| 	} | ||||
| 	if !errors.Is(werr, err) { | ||||
| 		t.Errorf("should be equal: %v", err) | ||||
| 	} | ||||
| 	if !errors.Is(werr, err2) { | ||||
| 		t.Errorf("should be equal: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	s.Code = 1 | ||||
| 	st.Code = 1 | ||||
| 	if !errors.Is(s, st) { | ||||
| 		t.Errorf("error is not match: %+v -> %+v", s, st) | ||||
| 	if !errors.As(err, &base) { | ||||
| 		t.Errorf("should be matchs: %v", err) | ||||
| 	} | ||||
| 	if !IsBadRequest(err) { | ||||
| 		t.Errorf("should be matchs: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	s.Reason = "test_reason" | ||||
| 	s.Reason = "test_reason" | ||||
|  | ||||
| 	if !errors.Is(s, st) { | ||||
| 		t.Errorf("error is not match: %+v -> %+v", s, st) | ||||
| 	if code := Code(err); code != err2.Code { | ||||
| 		t.Errorf("got %d want: %s", code, err) | ||||
| 	} | ||||
| 	if domain := Domain(err); domain != err2.Domain { | ||||
| 		t.Errorf("got %s want: %s", domain, err) | ||||
| 	} | ||||
| 	if reason := Reason(err); reason != err3.Reason { | ||||
| 		t.Errorf("got %s want: %s", reason, err) | ||||
| 	} | ||||
|  | ||||
| 	if Reason(s) != "test_reason" { | ||||
| 		t.Errorf("error is not match: %+v -> %+v", s, st) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestErrorIs(t *testing.T) { | ||||
| 	err1 := &StatusError{Code: 1} | ||||
| 	t.Log(err1) | ||||
| 	err2 := fmt.Errorf("wrap : %w", err1) | ||||
| 	t.Log(err2) | ||||
|  | ||||
| 	if !(errors.Is(err2, err1)) { | ||||
| 		t.Errorf("error is not match: a: %v b: %v ", err2, err1) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestErrorAs(t *testing.T) { | ||||
| 	err1 := &StatusError{Code: 1} | ||||
| 	err2 := fmt.Errorf("wrap : %w", err1) | ||||
|  | ||||
| 	err3 := new(StatusError) | ||||
| 	if !errors.As(err2, &err3) { | ||||
| 		t.Errorf("error is not match: %v", err2) | ||||
| 	if err3.Metadata["foo"] != "bar" { | ||||
| 		t.Error("not expected metadata") | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										80
									
								
								errors/types.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								errors/types.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| package errors | ||||
|  | ||||
| import "net/http" | ||||
|  | ||||
| // BadRequest new BadRequest error that is mapped to a 400 response. | ||||
| func BadRequest(reason, message string) *Error { | ||||
| 	return New(http.StatusBadRequest, reason, message) | ||||
| } | ||||
|  | ||||
| // IsBadRequest determines if err is an error which indicates a BadRequest error. | ||||
| // It supports wrapped errors. | ||||
| func IsBadRequest(err error) bool { | ||||
| 	return Code(err) == http.StatusBadRequest | ||||
| } | ||||
|  | ||||
| // Unauthorized new Unauthorized error that is mapped to a 401 response. | ||||
| func Unauthorized(reason, message string) *Error { | ||||
| 	return New(http.StatusUnauthorized, reason, message) | ||||
| } | ||||
|  | ||||
| // IsUnauthorized determines if err is an error which indicates a Unauthorized error. | ||||
| // It supports wrapped errors. | ||||
| func IsUnauthorized(err error) bool { | ||||
| 	return Code(err) == http.StatusUnauthorized | ||||
| } | ||||
|  | ||||
| // Forbidden new Forbidden error that is mapped to a 403 response. | ||||
| func Forbidden(reason, message string) *Error { | ||||
| 	return New(http.StatusForbidden, reason, message) | ||||
| } | ||||
|  | ||||
| // IsForbidden determines if err is an error which indicates a Forbidden error. | ||||
| // It supports wrapped errors. | ||||
| func IsForbidden(err error) bool { | ||||
| 	return Code(err) == http.StatusForbidden | ||||
| } | ||||
|  | ||||
| // NotFound new NotFound error that is mapped to a 404 response. | ||||
| func NotFound(reason, message string) *Error { | ||||
| 	return New(http.StatusNotFound, reason, message) | ||||
| } | ||||
|  | ||||
| // IsNotFound determines if err is an error which indicates an NotFound error. | ||||
| // It supports wrapped errors. | ||||
| func IsNotFound(err error) bool { | ||||
| 	return Code(err) == http.StatusNotFound | ||||
| } | ||||
|  | ||||
| // Conflict new Conflict error that is mapped to a 409 response. | ||||
| func Conflict(reason, message string) *Error { | ||||
| 	return New(http.StatusConflict, reason, message) | ||||
| } | ||||
|  | ||||
| // IsConflict determines if err is an error which indicates a Conflict error. | ||||
| // It supports wrapped errors. | ||||
| func IsConflict(err error) bool { | ||||
| 	return Code(err) == http.StatusConflict | ||||
| } | ||||
|  | ||||
| // InternalServer new InternalServer error that is mapped to a 500 response. | ||||
| func InternalServer(reason, message string) *Error { | ||||
| 	return New(http.StatusInternalServerError, reason, message) | ||||
| } | ||||
|  | ||||
| // IsInternalServer determines if err is an error which indicates an InternalServer error. | ||||
| // It supports wrapped errors. | ||||
| func IsInternalServer(err error) bool { | ||||
| 	return Code(err) == http.StatusInternalServerError | ||||
| } | ||||
|  | ||||
| // ServiceUnavailable new ServiceUnavailable error that is mapped to a HTTP 503 response. | ||||
| func ServiceUnavailable(reason, message string) *Error { | ||||
| 	return New(http.StatusServiceUnavailable, reason, message) | ||||
| } | ||||
|  | ||||
| // IsServiceUnavailable determines if err is an error which indicates a ServiceUnavailable error. | ||||
| // It supports wrapped errors. | ||||
| func IsServiceUnavailable(err error) bool { | ||||
| 	return Code(err) == http.StatusServiceUnavailable | ||||
| } | ||||
							
								
								
									
										32
									
								
								errors/types_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								errors/types_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| package errors | ||||
|  | ||||
| import "testing" | ||||
|  | ||||
| func TestTypes(t *testing.T) { | ||||
| 	var ( | ||||
| 		input = []*Error{ | ||||
| 			BadRequest("reason_400", "message_400"), | ||||
| 			Unauthorized("reason_401", "message_401"), | ||||
| 			Forbidden("reason_403", "message_403"), | ||||
| 			NotFound("reason_404", "message_404"), | ||||
| 			Conflict("reason_409", "message_409"), | ||||
| 			InternalServer("reason_500", "message_500"), | ||||
| 			ServiceUnavailable("reason_503", "message_503"), | ||||
| 		} | ||||
| 		output = []func(error) bool{ | ||||
| 			IsBadRequest, | ||||
| 			IsUnauthorized, | ||||
| 			IsForbidden, | ||||
| 			IsNotFound, | ||||
| 			IsConflict, | ||||
| 			IsInternalServer, | ||||
| 			IsServiceUnavailable, | ||||
| 		} | ||||
| 	) | ||||
|  | ||||
| 	for i, in := range input { | ||||
| 		if !output[i](in) { | ||||
| 			t.Errorf("not expect: %v", in) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -48,7 +48,7 @@ func Server(opts ...Option) middleware.Middleware { | ||||
| 			var ( | ||||
| 				method string | ||||
| 				path   string | ||||
| 				code   int32 | ||||
| 				code   int | ||||
| 			) | ||||
| 			if info, ok := grpc.FromServerContext(ctx); ok { | ||||
| 				method = "POST" | ||||
| @@ -90,7 +90,7 @@ func Client(opts ...Option) middleware.Middleware { | ||||
| 			var ( | ||||
| 				method string | ||||
| 				path   string | ||||
| 				code   int32 | ||||
| 				code   int | ||||
| 			) | ||||
| 			if info, ok := grpc.FromClientContext(ctx); ok { | ||||
| 				method = "POST" | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package recovery | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"runtime" | ||||
|  | ||||
| 	"github.com/go-kratos/kratos/v2/errors" | ||||
| @@ -39,7 +40,7 @@ func Recovery(opts ...Option) middleware.Middleware { | ||||
| 	options := options{ | ||||
| 		logger: log.DefaultLogger, | ||||
| 		handler: func(ctx context.Context, req, err interface{}) error { | ||||
| 			return errors.Unknown("Unknown", "panic triggered: %v", err) | ||||
| 			return errors.InternalServer("recovery", fmt.Sprintf("panic triggered: %v", err)) | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
|   | ||||
| @@ -2,28 +2,38 @@ package status | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/go-kratos/kratos/v2/errors" | ||||
| 	"github.com/go-kratos/kratos/v2/middleware" | ||||
|  | ||||
| 	//lint:ignore SA1019 grpc | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/golang/protobuf/ptypes" | ||||
| 	"google.golang.org/genproto/googleapis/rpc/errdetails" | ||||
| 	"google.golang.org/grpc/codes" | ||||
| 	"google.golang.org/grpc/status" | ||||
| ) | ||||
|  | ||||
| type domainKey struct{} | ||||
|  | ||||
| // HandlerFunc is middleware error handler. | ||||
| type HandlerFunc func(error) error | ||||
| type HandlerFunc func(context.Context, error) error | ||||
|  | ||||
| // Option is recovery option. | ||||
| type Option func(*options) | ||||
|  | ||||
| type options struct { | ||||
| 	domain  string | ||||
| 	handler HandlerFunc | ||||
| } | ||||
|  | ||||
| // WithDomain with service domain. | ||||
| func WithDomain(domain string) Option { | ||||
| 	return func(o *options) { | ||||
| 		o.domain = domain | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithHandler with status handler. | ||||
| func WithHandler(h HandlerFunc) Option { | ||||
| 	return func(o *options) { | ||||
| @@ -34,7 +44,7 @@ func WithHandler(h HandlerFunc) Option { | ||||
| // Server is an error middleware. | ||||
| func Server(opts ...Option) middleware.Middleware { | ||||
| 	options := options{ | ||||
| 		handler: errorEncode, | ||||
| 		handler: encodeErr, | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| @@ -43,7 +53,8 @@ func Server(opts ...Option) middleware.Middleware { | ||||
| 		return func(ctx context.Context, req interface{}) (interface{}, error) { | ||||
| 			reply, err := handler(ctx, req) | ||||
| 			if err != nil { | ||||
| 				return nil, options.handler(err) | ||||
| 				ctx = context.WithValue(ctx, domainKey{}, options.domain) | ||||
| 				return nil, options.handler(ctx, err) | ||||
| 			} | ||||
| 			return reply, nil | ||||
| 		} | ||||
| @@ -53,7 +64,7 @@ func Server(opts ...Option) middleware.Middleware { | ||||
| // Client is an error middleware. | ||||
| func Client(opts ...Option) middleware.Middleware { | ||||
| 	options := options{ | ||||
| 		handler: errorDecode, | ||||
| 		handler: decodeErr, | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| @@ -62,35 +73,26 @@ func Client(opts ...Option) middleware.Middleware { | ||||
| 		return func(ctx context.Context, req interface{}) (interface{}, error) { | ||||
| 			reply, err := handler(ctx, req) | ||||
| 			if err != nil { | ||||
| 				return nil, options.handler(err) | ||||
| 				return nil, options.handler(ctx, err) | ||||
| 			} | ||||
| 			return reply, nil | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func errorEncode(err error) error { | ||||
| 	se, ok := errors.FromError(err) | ||||
| 	if !ok { | ||||
| 		se = &errors.StatusError{ | ||||
| 			Code:    2, | ||||
| 			Message: err.Error(), | ||||
| 		} | ||||
| func encodeErr(ctx context.Context, err error) error { | ||||
| 	se := errors.FromError(err) | ||||
| 	if se.Domain == "" { | ||||
| 		se.Domain, _ = ctx.Value(domainKey{}).(string) | ||||
| 	} | ||||
| 	gs := status.Newf(codes.Code(se.Code), "%s: %s", se.Reason, se.Message) | ||||
| 	gs := status.Newf(httpToGRPCCode(se.Code), "%s: %s", se.Reason, se.Message) | ||||
| 	details := []proto.Message{ | ||||
| 		&errdetails.ErrorInfo{ | ||||
| 			Domain:   se.Domain, | ||||
| 			Reason:   se.Reason, | ||||
| 			Metadata: map[string]string{"message": se.Message}, | ||||
| 			Metadata: se.Metadata, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, any := range se.Details { | ||||
| 		detail := &ptypes.DynamicAny{} | ||||
| 		if err := ptypes.UnmarshalAny(any, detail); err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		details = append(details, detail.Message) | ||||
| 	} | ||||
| 	gs, err = gs.WithDetails(details...) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -98,19 +100,60 @@ func errorEncode(err error) error { | ||||
| 	return gs.Err() | ||||
| } | ||||
|  | ||||
| func errorDecode(err error) error { | ||||
| func decodeErr(ctx context.Context, err error) error { | ||||
| 	gs := status.Convert(err) | ||||
| 	se := &errors.StatusError{ | ||||
| 		Code:    int32(gs.Code()), | ||||
| 		Details: gs.Proto().Details, | ||||
| 	se := &errors.Error{ | ||||
| 		Code:    grpcToHTTPCode(gs.Code()), | ||||
| 		Message: gs.Message(), | ||||
| 	} | ||||
| 	for _, detail := range gs.Details() { | ||||
| 		switch d := detail.(type) { | ||||
| 		case *errdetails.ErrorInfo: | ||||
| 			se.Domain = d.Domain | ||||
| 			se.Reason = d.Reason | ||||
| 			se.Message = d.Metadata["message"] | ||||
| 			se.Metadata = d.Metadata | ||||
| 			return se | ||||
| 		} | ||||
| 	} | ||||
| 	return se | ||||
| } | ||||
|  | ||||
| func httpToGRPCCode(code int) codes.Code { | ||||
| 	switch code { | ||||
| 	case http.StatusBadRequest: | ||||
| 		return codes.InvalidArgument | ||||
| 	case http.StatusUnauthorized: | ||||
| 		return codes.Unauthenticated | ||||
| 	case http.StatusForbidden: | ||||
| 		return codes.PermissionDenied | ||||
| 	case http.StatusNotFound: | ||||
| 		return codes.NotFound | ||||
| 	case http.StatusConflict: | ||||
| 		return codes.Aborted | ||||
| 	case http.StatusInternalServerError: | ||||
| 		return codes.Internal | ||||
| 	case http.StatusServiceUnavailable: | ||||
| 		return codes.Unavailable | ||||
| 	} | ||||
| 	return codes.Unknown | ||||
| } | ||||
|  | ||||
| func grpcToHTTPCode(code codes.Code) int { | ||||
| 	switch code { | ||||
| 	case codes.InvalidArgument: | ||||
| 		return http.StatusBadRequest | ||||
| 	case codes.Unauthenticated: | ||||
| 		return http.StatusUnauthorized | ||||
| 	case codes.PermissionDenied: | ||||
| 		return http.StatusForbidden | ||||
| 	case codes.NotFound: | ||||
| 		return http.StatusNotFound | ||||
| 	case codes.Aborted: | ||||
| 		return http.StatusConflict | ||||
| 	case codes.Internal: | ||||
| 		return http.StatusInternalServerError | ||||
| 	case codes.Unavailable: | ||||
| 		return http.StatusServiceUnavailable | ||||
| 	} | ||||
| 	return http.StatusInternalServerError | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package status | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/go-kratos/kratos/v2/errors" | ||||
| @@ -9,13 +10,13 @@ import ( | ||||
| ) | ||||
|  | ||||
| func TestErrEncoder(t *testing.T) { | ||||
| 	err := errors.InvalidArgument("InvalidArgument", "format") | ||||
| 	en := errorEncode(err) | ||||
| 	err := errors.BadRequest("InvalidArgument", "format") | ||||
| 	en := encodeErr(context.Background(), err) | ||||
| 	if code := status.Code(en); code != codes.InvalidArgument { | ||||
| 		t.Errorf("expected %d got %d", codes.InvalidArgument, code) | ||||
| 	} | ||||
| 	de := errorDecode(en) | ||||
| 	if !errors.IsInvalidArgument(de) { | ||||
| 	de := decodeErr(context.Background(), en) | ||||
| 	if !errors.IsBadRequest(de) { | ||||
| 		t.Errorf("expected %v got %v", err, de) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ func Validator() middleware.Middleware { | ||||
| 		return func(ctx context.Context, req interface{}) (reply interface{}, err error) { | ||||
| 			if v, ok := req.(validator); ok { | ||||
| 				if err := v.Validate(); err != nil { | ||||
| 					return nil, errors.InvalidArgument("Validator", err.Error()) | ||||
| 					return nil, errors.BadRequest("validator", err.Error()) | ||||
| 				} | ||||
| 			} | ||||
| 			return handler(ctx, req) | ||||
|   | ||||
| @@ -117,7 +117,7 @@ func Do(client *http.Client, req *http.Request, target interface{}) error { | ||||
| 	} | ||||
| 	defer res.Body.Close() | ||||
| 	if res.StatusCode < 200 || res.StatusCode > 299 { | ||||
| 		se := &errors.StatusError{Code: 2} | ||||
| 		se := &errors.Error{Code: 500} | ||||
| 		if err := decodeResponse(res, se); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|   | ||||
| @@ -108,17 +108,11 @@ func encodeResponse(w http.ResponseWriter, r *http.Request, v interface{}) error | ||||
|  | ||||
| // encodeError encodes the error to the HTTP response. | ||||
| func encodeError(w http.ResponseWriter, r *http.Request, err error) { | ||||
| 	se, ok := errors.FromError(err) | ||||
| 	if !ok { | ||||
| 		se = &errors.StatusError{ | ||||
| 			Code:    2, | ||||
| 			Message: err.Error(), | ||||
| 		} | ||||
| 	} | ||||
| 	se := errors.FromError(err) | ||||
| 	codec := codecForRequest(r) | ||||
| 	data, _ := codec.Marshal(se) | ||||
| 	w.Header().Set(contentTypeHeader, contentType(codec.Name())) | ||||
| 	w.WriteHeader(se.HTTPStatus()) | ||||
| 	w.WriteHeader(se.Code) | ||||
| 	_, _ = w.Write(data) | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user