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.
81 lines
2.1 KiB
81 lines
2.1 KiB
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)
|
|
}
|
|
|