优化方法的使用
This commit is contained in:
Regular → Executable
+78
-58
@@ -6,12 +6,10 @@ package responsex
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"net/http"
|
||||
|
||||
"github.com/yuninks/errorx"
|
||||
"github.com/yuninks/langx"
|
||||
"github.com/zeromicro/go-zero/core/trace"
|
||||
)
|
||||
|
||||
type response struct {
|
||||
@@ -22,39 +20,39 @@ type response struct {
|
||||
TraceId string `json:"trace_id,omitempty"`
|
||||
}
|
||||
|
||||
type Pagination struct {
|
||||
Page int64 `json:"page"`
|
||||
Size int64 `json:"size"`
|
||||
TotalPage int64 `json:"total_page"`
|
||||
TotalCount int64 `json:"total_count"`
|
||||
// 成功文案的多语言 key(独立 key,避免与 errorx 预注册的 "success" 冲突)
|
||||
const successMsgKey = "responsex_success"
|
||||
|
||||
// 内置默认成功文案,也用作 defaultOptions 的初值
|
||||
const defaultSuccessMessage = "请求成功"
|
||||
|
||||
// SuccessMessageCtx 按 ctx 语言解析成功文案:
|
||||
// 1. 显式配置过 SetDefaultSuccessMessage → 用配置值;
|
||||
// 2. 注册过 key "responsex_success" → 用该语言的译文;
|
||||
// 3. 都没有 → 内置默认文案。
|
||||
//
|
||||
// 多语言接入示例(由调用方决定何时注册):
|
||||
//
|
||||
// langx.AppendCode(map[string]int{"responsex_success": 200})
|
||||
// langx.AppendTrans("zh", map[string]string{"responsex_success": "请求成功"})
|
||||
// langx.AppendTrans("en", map[string]string{"responsex_success": "success"})
|
||||
//
|
||||
// Success 系列内部使用同一套解析逻辑,无需额外配置。
|
||||
func SuccessMessageCtx(ctx context.Context) string {
|
||||
return resolveSuccessMessage(ctx)
|
||||
}
|
||||
|
||||
// 计算DB分页偏移量
|
||||
func GetOffset(page, size int) (offset int, limit int) {
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
func resolveSuccessMessage(ctx context.Context) string {
|
||||
if op != nil && op.successMsgSet {
|
||||
return op.defaultSuccessMessage
|
||||
}
|
||||
offset = (page - 1) * size
|
||||
limit = size
|
||||
if limit == 0 {
|
||||
// 默认查10条
|
||||
limit = 10
|
||||
if msg := langx.GetMsgCtx(ctx, successMsgKey); msg != successMsgKey {
|
||||
return msg
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 计算响应分页
|
||||
func GetPage(page, size, totalCount int64) Pagination {
|
||||
pa := Pagination{}
|
||||
totalPage := 0
|
||||
if size != 0 {
|
||||
totalPage = int(math.Ceil(float64(totalCount) / float64(size)))
|
||||
if op != nil {
|
||||
return op.defaultSuccessMessage
|
||||
}
|
||||
pa.Page = page
|
||||
pa.Size = size
|
||||
pa.TotalPage = int64(totalPage)
|
||||
pa.TotalCount = totalCount
|
||||
return pa
|
||||
return defaultSuccessMessage
|
||||
}
|
||||
|
||||
// Msg格式化响应
|
||||
@@ -67,13 +65,13 @@ func FormatMessage(ctx context.Context, w http.ResponseWriter, msgKey string, fo
|
||||
|
||||
// 成功的响应
|
||||
func Success(ctx context.Context, w http.ResponseWriter, data any, ops ...Option) {
|
||||
baseOps := []Option{SetCode(op.defaultSuccessCode), SetMessage("请求成功"), SetData(data)}
|
||||
baseOps := []Option{SetCode(op.defaultSuccessCode), SetMessage(resolveSuccessMessage(ctx)), SetData(data)}
|
||||
baseOps = append(baseOps, ops...)
|
||||
ResponseCtx(ctx, w, baseOps...)
|
||||
}
|
||||
|
||||
func SuccessWithPage(ctx context.Context, w http.ResponseWriter, data any, page *Pagination, ops ...Option) {
|
||||
baseOps := []Option{SetCode(op.defaultSuccessCode), SetMessage("请求成功"), SetData(data), SetPage(page)}
|
||||
baseOps := []Option{SetCode(op.defaultSuccessCode), SetMessage(resolveSuccessMessage(ctx)), SetData(data), SetPage(page)}
|
||||
baseOps = append(baseOps, ops...)
|
||||
ResponseCtx(ctx, w, baseOps...)
|
||||
}
|
||||
@@ -87,9 +85,7 @@ func ErrorWithData(ctx context.Context, w http.ResponseWriter, err error, data i
|
||||
code := op.defaultErrorCode
|
||||
msg := "请求失败"
|
||||
if err != nil {
|
||||
val,ok := errorx.As(err)
|
||||
if ok {
|
||||
|
||||
if val, ok := errorx.As(err); ok {
|
||||
if langx.GetDefaultCode() != val.Code() {
|
||||
code = val.Code()
|
||||
}
|
||||
@@ -102,19 +98,21 @@ func ErrorWithData(ctx context.Context, w http.ResponseWriter, err error, data i
|
||||
}
|
||||
|
||||
func ErrorStr(ctx context.Context, w http.ResponseWriter, msg string, ops ...Option) {
|
||||
msg = langx.GetMsgCtx(ctx, msg)
|
||||
code := langx.GetCode(msg)
|
||||
if code == langx.GetDefaultCode() {
|
||||
code = op.defaultErrorCode
|
||||
translated := langx.GetMsgCtx(ctx, msg)
|
||||
// msg 命中语言表时按 key 取其业务码;未命中则保持默认错误码
|
||||
code := op.defaultErrorCode
|
||||
if translated != msg {
|
||||
if c := langx.GetCode(msg); c != langx.GetDefaultCode() {
|
||||
code = c
|
||||
}
|
||||
}
|
||||
baseOps := []Option{SetCode(code), SetMessage(msg)}
|
||||
baseOps := []Option{SetCode(code), SetMessage(translated)}
|
||||
baseOps = append(baseOps, ops...)
|
||||
ResponseCtx(ctx, w, baseOps...)
|
||||
}
|
||||
|
||||
// 基础的响应
|
||||
func ResponseCtx(ctx context.Context, w http.ResponseWriter, ops ...Option) {
|
||||
|
||||
def := defaultOptions() // 默认值
|
||||
for _, o := range ops {
|
||||
o(def)
|
||||
@@ -126,27 +124,36 @@ func ResponseCtx(ctx context.Context, w http.ResponseWriter, ops ...Option) {
|
||||
resp.Data = def.data
|
||||
resp.Pagination = def.pagination
|
||||
|
||||
// 获取trace_id
|
||||
if def.traceId != "" {
|
||||
t := ctx.Value(def.traceId)
|
||||
if t != nil {
|
||||
val, ok := t.(string)
|
||||
if ok {
|
||||
resp.TraceId = val
|
||||
}
|
||||
} else {
|
||||
// go-zero
|
||||
resp.TraceId = trace.TraceIDFromContext(ctx)
|
||||
}
|
||||
if def.traceFunc != nil {
|
||||
resp.TraceId = def.traceFunc(ctx)
|
||||
}
|
||||
|
||||
bs, _ := json.Marshal(resp)
|
||||
bs, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
// 序列化失败不能回空 body,否则客户端无法解析
|
||||
logError(ctx, def, "response marshal failed err:%+v", err)
|
||||
fallback := response{
|
||||
Code: op.defaultErrorCode,
|
||||
Message: "响应序列化失败",
|
||||
}
|
||||
if def.traceFunc != nil {
|
||||
fallback.TraceId = def.traceFunc(ctx)
|
||||
}
|
||||
bs, _ = json.Marshal(fallback)
|
||||
writeResponse(ctx, w, def, bs, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !def.ignoreLog {
|
||||
// 记录日志
|
||||
def.logger.Info(ctx, "response:", string(bs))
|
||||
logInfo(ctx, def, "response:", string(bs))
|
||||
}
|
||||
|
||||
writeResponse(ctx, w, def, bs, def.httpStatusCode)
|
||||
}
|
||||
|
||||
// writeResponse 统一写响应,httpStatus 为 0 时按 200 处理
|
||||
func writeResponse(ctx context.Context, w http.ResponseWriter, def *options, bs []byte, httpStatus int) {
|
||||
// 写入自定义响应头
|
||||
for k, v := range def.headers {
|
||||
w.Header().Set(k, v)
|
||||
@@ -154,8 +161,6 @@ func ResponseCtx(ctx context.Context, w http.ResponseWriter, ops ...Option) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
// 确定HTTP状态码
|
||||
httpStatus := def.httpStatusCode
|
||||
if httpStatus == 0 {
|
||||
httpStatus = 200
|
||||
}
|
||||
@@ -163,6 +168,21 @@ func ResponseCtx(ctx context.Context, w http.ResponseWriter, ops ...Option) {
|
||||
|
||||
n, err := w.Write(bs)
|
||||
if err != nil || n != len(bs) {
|
||||
op.logger.Error(ctx, "write response failed err:%+v", err)
|
||||
logError(ctx, def, "write response failed err:%+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// logInfo / logError 使用本次响应的 logger(SetLogger 生效),并做空值保护
|
||||
func logInfo(ctx context.Context, def *options, args ...interface{}) {
|
||||
if def == nil || def.logger == nil {
|
||||
return
|
||||
}
|
||||
def.logger.Info(ctx, args...)
|
||||
}
|
||||
|
||||
func logError(ctx context.Context, def *options, format string, args ...interface{}) {
|
||||
if def == nil || def.logger == nil {
|
||||
return
|
||||
}
|
||||
def.logger.Errorf(ctx, format, args...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user