You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kratos/transport/http/default.go

82 lines
2.1 KiB

4 years ago
package http
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/go-kratos/kratos/v2/encoding"
)
const baseContentType = "application"
func contentType(subtype string) string {
return strings.Join([]string{baseContentType, subtype}, "/")
}
func contentSubtype(contentType string) string {
if contentType == baseContentType {
return ""
}
if !strings.HasPrefix(contentType, baseContentType) {
return ""
}
// guaranteed since != baseContentType and has baseContentType prefix
switch contentType[len(baseContentType)] {
case '/', ';':
// this will return true for "application/grpc+" or "application/grpc;"
// which the previous validContentType function tested to be valid, so we
// just say that no content-subtype is specified in this case
return contentType[len(baseContentType)+1:]
default:
return ""
}
}
func defaultRequestDecoder(req *http.Request, v interface{}) error {
data, err := ioutil.ReadAll(req.Body)
if err != nil {
return err
}
defer req.Body.Close()
subtype := contentSubtype(req.Header.Get("content-type"))
codec := encoding.GetCodec(subtype)
if codec == nil {
return fmt.Errorf("decoding request failed unknown content-type: %s", subtype)
}
return codec.Unmarshal(data, v)
}
func defaultResponseEncoder(res http.ResponseWriter, req *http.Request, v interface{}) error {
subtype := contentSubtype(req.Header.Get("accept"))
codec := encoding.GetCodec(subtype)
if codec == nil {
codec = encoding.GetCodec("json")
}
data, err := codec.Marshal(v)
if err != nil {
return err
}
res.Header().Set("content-type", contentType(codec.Name()))
res.Write(data)
return nil
}
func defaultErrorEncoder(res http.ResponseWriter, req *http.Request, err error) {
se, code := StatusError(err)
subtype := contentSubtype(req.Header.Get("accept"))
codec := encoding.GetCodec(subtype)
if codec == nil {
codec = encoding.GetCodec("json")
}
data, err := codec.Marshal(se)
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
return
}
res.Header().Set("content-type", contentType(codec.Name()))
res.WriteHeader(code)
res.Write(data)
}