handle.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package http
  2. import (
  3. "io/ioutil"
  4. "net/http"
  5. "strings"
  6. "github.com/go-kratos/kratos/v2/transport/http/binding"
  7. "google.golang.org/protobuf/types/known/emptypb"
  8. "github.com/go-kratos/kratos/v2/encoding"
  9. "github.com/go-kratos/kratos/v2/errors"
  10. "git.ikuban.com/server/kratos-utils/http/encoding/json"
  11. _ "github.com/go-kratos/kratos/v2/encoding/proto"
  12. )
  13. // decodeRequest decodes the request body to object.
  14. func DecodeRequest(req *http.Request, v interface{}) error {
  15. method := strings.ToUpper(req.Method)
  16. if method == "POST" || method == "PUT" || method == "DELETE" {
  17. if _, ok := v.(*emptypb.Empty); ok {
  18. return binding.BindForm(req, v)
  19. }
  20. subtype := contentSubtype(req.Header.Get(ContentTypeHeader))
  21. if codec := encoding.GetCodec(subtype); codec != nil {
  22. data, err := ioutil.ReadAll(req.Body)
  23. if err != nil {
  24. return err
  25. }
  26. return codec.Unmarshal(data, v)
  27. }
  28. }
  29. return binding.BindForm(req, v)
  30. }
  31. // encodeResponse encodes the object to the HTTP response.
  32. func EncodeResponse(w http.ResponseWriter, r *http.Request, v interface{}) error {
  33. codec := codecForRequest(r)
  34. data, err := codec.Marshal(v)
  35. if err != nil {
  36. return err
  37. }
  38. w.Header().Set(ContentTypeHeader, contentType(codec.Name()))
  39. _, _ = w.Write(data)
  40. return nil
  41. }
  42. func ErrHandle(w http.ResponseWriter, r *http.Request, err error) {
  43. se, ok := errors.FromError(err)
  44. if !ok {
  45. se = &errors.StatusError{
  46. Code: 10500,
  47. Message: err.Error(),
  48. }
  49. }
  50. if se.Code == -1 {
  51. return
  52. }
  53. codec := codecForRequest(r)
  54. w.Header().Set(ContentTypeHeader, contentType(codec.Name()))
  55. if se.Code == 0 {
  56. w.WriteHeader(200)
  57. } else if se.Code >= 302 && se.Code <= 303 {
  58. w.WriteHeader(int(se.Code))
  59. http.Redirect(w, r, se.Message, int(se.Code))
  60. return
  61. } else {
  62. if se.Code < 10000 {
  63. se.Code = 10000 + se.Code
  64. }
  65. if se.Code < 10100 && se.Message == "" {
  66. se.Message = "系统错误"
  67. }
  68. w.WriteHeader(400)
  69. }
  70. data, _ := codec.Marshal(se)
  71. _, _ = w.Write(data)
  72. }
  73. const baseContentType = "application"
  74. var (
  75. acceptHeader = http.CanonicalHeaderKey("Accept")
  76. ContentTypeHeader = http.CanonicalHeaderKey("Content-Type")
  77. )
  78. func contentType(subtype string) string {
  79. return strings.Join([]string{baseContentType, subtype}, "/")
  80. }
  81. // codecForRequest get encoding.Codec via http.Request
  82. func codecForRequest(r *http.Request) encoding.Codec {
  83. var codec encoding.Codec
  84. for _, accept := range r.Header[acceptHeader] {
  85. codeName := contentSubtype(accept)
  86. if codeName == "json" {
  87. codec = encoding.GetCodec(json.Name)
  88. break
  89. }
  90. if codec = encoding.GetCodec(codeName); codec != nil {
  91. break
  92. }
  93. }
  94. if codec == nil {
  95. codec = encoding.GetCodec(json.Name)
  96. }
  97. return codec
  98. }
  99. func contentSubtype(contentType string) string {
  100. if contentType == baseContentType {
  101. return ""
  102. }
  103. if !strings.HasPrefix(contentType, baseContentType) {
  104. return ""
  105. }
  106. switch contentType[len(baseContentType)] {
  107. case '/', ';':
  108. if i := strings.Index(contentType, ";"); i != -1 {
  109. return contentType[len(baseContentType)+1 : i]
  110. }
  111. return contentType[len(baseContentType)+1:]
  112. default:
  113. return ""
  114. }
  115. }