mirror of
https://github.com/go-kratos/kratos.git
synced 2026-05-16 09:48:28 +02:00
errors: add errors coder (#946)
* add errors coder * rename internal http to httputil * add errors proto
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
const (
|
||||
baseContentType = "application"
|
||||
)
|
||||
|
||||
// ContentType returns the content-type with base prefix.
|
||||
func ContentType(subtype string) string {
|
||||
return strings.Join([]string{baseContentType, subtype}, "/")
|
||||
}
|
||||
|
||||
// ContentSubtype returns the content-subtype for the given content-type. The
|
||||
// given content-type must be a valid content-type that starts with
|
||||
// but no content-subtype will be returned.
|
||||
// according rfc7231.
|
||||
// contentType is assumed to be lowercase already.
|
||||
func ContentSubtype(contentType string) string {
|
||||
left := strings.Index(contentType, "/")
|
||||
if left == -1 {
|
||||
return ""
|
||||
}
|
||||
right := strings.Index(contentType, ";")
|
||||
if right == -1 {
|
||||
right = len(contentType)
|
||||
}
|
||||
if right < left {
|
||||
return ""
|
||||
}
|
||||
return contentType[left+1 : right]
|
||||
}
|
||||
|
||||
// GRPCCodeFromStatus converts a HTTP error code into the corresponding gRPC response status.
|
||||
// See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
|
||||
func GRPCCodeFromStatus(code int) codes.Code {
|
||||
switch code {
|
||||
case http.StatusOK:
|
||||
return codes.OK
|
||||
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.StatusTooManyRequests:
|
||||
return codes.ResourceExhausted
|
||||
case http.StatusInternalServerError:
|
||||
return codes.Internal
|
||||
case http.StatusNotImplemented:
|
||||
return codes.Unimplemented
|
||||
case http.StatusServiceUnavailable:
|
||||
return codes.Unavailable
|
||||
case http.StatusGatewayTimeout:
|
||||
return codes.DeadlineExceeded
|
||||
}
|
||||
return codes.Unknown
|
||||
}
|
||||
|
||||
// StatusFromGRPCCode converts a gRPC error code into the corresponding HTTP response status.
|
||||
// See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
|
||||
func StatusFromGRPCCode(code codes.Code) int {
|
||||
switch code {
|
||||
case codes.OK:
|
||||
return http.StatusOK
|
||||
case codes.Canceled:
|
||||
return http.StatusRequestTimeout
|
||||
case codes.Unknown:
|
||||
return http.StatusInternalServerError
|
||||
case codes.InvalidArgument:
|
||||
return http.StatusBadRequest
|
||||
case codes.DeadlineExceeded:
|
||||
return http.StatusGatewayTimeout
|
||||
case codes.NotFound:
|
||||
return http.StatusNotFound
|
||||
case codes.AlreadyExists:
|
||||
return http.StatusConflict
|
||||
case codes.PermissionDenied:
|
||||
return http.StatusForbidden
|
||||
case codes.Unauthenticated:
|
||||
return http.StatusUnauthorized
|
||||
case codes.ResourceExhausted:
|
||||
return http.StatusTooManyRequests
|
||||
case codes.FailedPrecondition:
|
||||
return http.StatusBadRequest
|
||||
case codes.Aborted:
|
||||
return http.StatusConflict
|
||||
case codes.OutOfRange:
|
||||
return http.StatusBadRequest
|
||||
case codes.Unimplemented:
|
||||
return http.StatusNotImplemented
|
||||
case codes.Internal:
|
||||
return http.StatusInternalServerError
|
||||
case codes.Unavailable:
|
||||
return http.StatusServiceUnavailable
|
||||
case codes.DataLoss:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package httputil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestContentSubtype(t *testing.T) {
|
||||
tests := []struct {
|
||||
contentType string
|
||||
want string
|
||||
}{
|
||||
{"text/html; charset=utf-8", "html"},
|
||||
{"multipart/form-data; boundary=something", "form-data"},
|
||||
{"application/json; charset=utf-8", "json"},
|
||||
{"application/json", "json"},
|
||||
{"application/xml", "xml"},
|
||||
{"text/xml", "xml"},
|
||||
{";text/xml", ""},
|
||||
{"application", ""},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.contentType, func(t *testing.T) {
|
||||
got := ContentSubtype(test.contentType)
|
||||
if got != test.want {
|
||||
t.Fatalf("want %v got %v", test.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user