response.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package response
  2. import (
  3. "context"
  4. "errors"
  5. "net/http"
  6. "os"
  7. "github.com/zeromicro/go-zero/core/logx"
  8. "github.com/zeromicro/go-zero/rest/httpx"
  9. "go.opentelemetry.io/otel/trace"
  10. )
  11. // Body 是统一 HTTP 响应体,格式与前端 API.Result<T> 对齐:
  12. // 成功:{ "success": true, "data": ... }
  13. // 失败:{ "success": false, "errorCode": N, "errorMessage": "...", "showType": N }
  14. type Body struct {
  15. Success bool `json:"success"`
  16. Data interface{} `json:"data,omitempty"`
  17. ErrorCode int `json:"errorCode,omitempty"`
  18. ErrorMessage string `json:"errorMessage,omitempty"`
  19. ShowType int `json:"showType,omitempty"`
  20. TraceId string `json:"traceId,omitempty"`
  21. Host string `json:"host,omitempty"`
  22. }
  23. // ShowType 与前端 ErrorShowType 枚举对齐
  24. const (
  25. ShowTypeSilent = 0 // SILENT
  26. ShowTypeWarnMessage = 1 // WARN_MESSAGE
  27. ShowTypeErrorMessage = 2 // ERROR_MESSAGE
  28. ShowTypeNotification = 4 // NOTIFICATION
  29. ShowTypeRedirect = 9 // REDIRECT
  30. )
  31. var hostname string
  32. func init() {
  33. hostname, _ = os.Hostname()
  34. }
  35. type CodeError struct {
  36. code int
  37. msg string
  38. showType int
  39. }
  40. func NewCodeError(code int, msg string) *CodeError {
  41. return &CodeError{code: code, msg: msg, showType: ShowTypeErrorMessage}
  42. }
  43. func (e *CodeError) Error() string { return e.msg }
  44. func (e *CodeError) Code() int { return e.code }
  45. func (e *CodeError) ShowType() int { return e.showType }
  46. func ErrBadRequest(msg string) *CodeError { return NewCodeError(400, msg) }
  47. func ErrUnauthorized(msg string) *CodeError { return NewCodeError(401, msg) }
  48. func ErrForbidden(msg string) *CodeError { return NewCodeError(403, msg) }
  49. func ErrNotFound(msg string) *CodeError { return NewCodeError(404, msg) }
  50. func ErrConflict(msg string) *CodeError { return NewCodeError(409, msg) }
  51. func ErrTooManyRequests(msg string) *CodeError { return NewCodeError(429, msg) }
  52. func traceIdFromCtx(ctx context.Context) string {
  53. if sc := trace.SpanFromContext(ctx).SpanContext(); sc.IsValid() {
  54. return sc.TraceID().String()
  55. }
  56. return ""
  57. }
  58. func Setup() {
  59. httpx.SetOkHandler(func(_ context.Context, v any) any {
  60. if v == nil {
  61. return Body{Success: true, Host: hostname}
  62. }
  63. return Body{Success: true, Data: v, Host: hostname}
  64. })
  65. httpx.SetErrorHandlerCtx(func(ctx context.Context, err error) (int, any) {
  66. traceId := traceIdFromCtx(ctx)
  67. var ce *CodeError
  68. if errors.As(err, &ce) {
  69. return http.StatusOK, Body{
  70. Success: false,
  71. ErrorCode: ce.Code(),
  72. ErrorMessage: ce.Error(),
  73. ShowType: ce.ShowType(),
  74. TraceId: traceId,
  75. Host: hostname,
  76. }
  77. }
  78. logx.WithContext(ctx).Errorf("internal error: %+v", err)
  79. return http.StatusOK, Body{
  80. Success: false,
  81. ErrorCode: 500,
  82. ErrorMessage: "服务器内部错误",
  83. ShowType: ShowTypeErrorMessage,
  84. TraceId: traceId,
  85. Host: hostname,
  86. }
  87. })
  88. }