handle.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package http
  2. import (
  3. "net/http"
  4. "strings"
  5. "github.com/go-kratos/kratos/v2/errors"
  6. "github.com/go-kratos/kratos/v2/encoding/json"
  7. "google.golang.org/grpc/encoding"
  8. )
  9. func ErrHandle(w http.ResponseWriter, r *http.Request, err error) {
  10. se, ok := errors.FromError(err)
  11. if !ok {
  12. se = &errors.StatusError{
  13. Code: 2,
  14. Message: err.Error(),
  15. }
  16. }
  17. codec := codecForRequest(r)
  18. data, _ := codec.Marshal(se)
  19. w.Header().Set(ContentTypeHeader, contentType(codec.Name()))
  20. w.WriteHeader(200)
  21. _, _ = w.Write(data)
  22. }
  23. const baseContentType = "application"
  24. var (
  25. acceptHeader = http.CanonicalHeaderKey("Accept")
  26. ContentTypeHeader = http.CanonicalHeaderKey("Content-Type")
  27. )
  28. func contentType(subtype string) string {
  29. return strings.Join([]string{baseContentType, subtype}, "/")
  30. }
  31. // codecForRequest get encoding.Codec via http.Request
  32. func codecForRequest(r *http.Request) encoding.Codec {
  33. var codec encoding.Codec
  34. for _, accept := range r.Header[acceptHeader] {
  35. if codec = encoding.GetCodec(contentSubtype(accept)); codec != nil {
  36. break
  37. }
  38. }
  39. if codec == nil {
  40. codec = encoding.GetCodec(json.Name)
  41. }
  42. return codec
  43. }
  44. func contentSubtype(contentType string) string {
  45. if contentType == baseContentType {
  46. return ""
  47. }
  48. if !strings.HasPrefix(contentType, baseContentType) {
  49. return ""
  50. }
  51. switch contentType[len(baseContentType)] {
  52. case '/', ';':
  53. if i := strings.Index(contentType, ";"); i != -1 {
  54. return contentType[len(baseContentType)+1 : i]
  55. }
  56. return contentType[len(baseContentType)+1:]
  57. default:
  58. return ""
  59. }
  60. }