handle.go 1.7 KB

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