handle.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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/errors"
  7. "git.ikuban.com/server/kratos-utils/http/encoding/jsonpb"
  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. w.Header().Set(ContentTypeHeader, contentType(codec.Name()))
  23. if se.Code == 0 {
  24. w.WriteHeader(200)
  25. } else {
  26. if se.Code < 10000 {
  27. se.Code = 10000 + se.Code
  28. }
  29. if se.Code < 10100 && se.Message == "" {
  30. se.Message = "系统错误"
  31. }
  32. w.WriteHeader(400)
  33. }
  34. data, _ := codec.Marshal(se)
  35. _, _ = w.Write(data)
  36. }
  37. const baseContentType = "application"
  38. var (
  39. acceptHeader = http.CanonicalHeaderKey("Accept")
  40. ContentTypeHeader = http.CanonicalHeaderKey("Content-Type")
  41. )
  42. func contentType(subtype string) string {
  43. return strings.Join([]string{baseContentType, subtype}, "/")
  44. }
  45. // codecForRequest get encoding.Codec via http.Request
  46. func codecForRequest(r *http.Request) encoding.Codec {
  47. var codec encoding.Codec
  48. for _, accept := range r.Header[acceptHeader] {
  49. codeName := contentSubtype(accept)
  50. if codeName == "json" {
  51. codec = encoding.GetCodec(jsonpb.Name)
  52. break
  53. }
  54. if codec = encoding.GetCodec(codeName); codec != nil {
  55. break
  56. }
  57. }
  58. if codec == nil {
  59. codec = encoding.GetCodec(jsonpb.Name)
  60. }
  61. return codec
  62. }
  63. func contentSubtype(contentType string) string {
  64. if contentType == baseContentType {
  65. return ""
  66. }
  67. if !strings.HasPrefix(contentType, baseContentType) {
  68. return ""
  69. }
  70. switch contentType[len(baseContentType)] {
  71. case '/', ';':
  72. if i := strings.Index(contentType, ";"); i != -1 {
  73. return contentType[len(baseContentType)+1 : i]
  74. }
  75. return contentType[len(baseContentType)+1:]
  76. default:
  77. return ""
  78. }
  79. }