package response import ( "context" "errors" "net/http" "os" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/rest/httpx" "go.opentelemetry.io/otel/trace" ) // Body 是统一 HTTP 响应体,格式与前端 API.Result 对齐: // 成功:{ "success": true, "data": ... } // 失败:{ "success": false, "errorCode": N, "errorMessage": "...", "showType": N } type Body struct { Success bool `json:"success"` Data interface{} `json:"data,omitempty"` ErrorCode int `json:"errorCode,omitempty"` ErrorMessage string `json:"errorMessage,omitempty"` ShowType int `json:"showType,omitempty"` TraceId string `json:"traceId,omitempty"` Host string `json:"host,omitempty"` } // ShowType 与前端 ErrorShowType 枚举对齐 const ( ShowTypeSilent = 0 // SILENT ShowTypeWarnMessage = 1 // WARN_MESSAGE ShowTypeErrorMessage = 2 // ERROR_MESSAGE ShowTypeNotification = 4 // NOTIFICATION ShowTypeRedirect = 9 // REDIRECT ) var hostname string func init() { hostname, _ = os.Hostname() } type CodeError struct { code int msg string showType int } func NewCodeError(code int, msg string) *CodeError { return &CodeError{code: code, msg: msg, showType: ShowTypeErrorMessage} } func (e *CodeError) Error() string { return e.msg } func (e *CodeError) Code() int { return e.code } func (e *CodeError) ShowType() int { return e.showType } func ErrBadRequest(msg string) *CodeError { return NewCodeError(400, msg) } func ErrUnauthorized(msg string) *CodeError { return NewCodeError(401, msg) } func ErrForbidden(msg string) *CodeError { return NewCodeError(403, msg) } func ErrNotFound(msg string) *CodeError { return NewCodeError(404, msg) } func ErrConflict(msg string) *CodeError { return NewCodeError(409, msg) } func ErrTooManyRequests(msg string) *CodeError { return NewCodeError(429, msg) } func traceIdFromCtx(ctx context.Context) string { if sc := trace.SpanFromContext(ctx).SpanContext(); sc.IsValid() { return sc.TraceID().String() } return "" } func Setup() { httpx.SetOkHandler(func(_ context.Context, v any) any { if v == nil { return Body{Success: true, Host: hostname} } return Body{Success: true, Data: v, Host: hostname} }) httpx.SetErrorHandlerCtx(func(ctx context.Context, err error) (int, any) { traceId := traceIdFromCtx(ctx) var ce *CodeError if errors.As(err, &ce) { return http.StatusOK, Body{ Success: false, ErrorCode: ce.Code(), ErrorMessage: ce.Error(), ShowType: ce.ShowType(), TraceId: traceId, Host: hostname, } } logx.WithContext(ctx).Errorf("internal error: %+v", err) return http.StatusOK, Body{ Success: false, ErrorCode: 500, ErrorMessage: "服务器内部错误", ShowType: ShowTypeErrorMessage, TraceId: traceId, Host: hostname, } }) }