优化方法的使用

This commit is contained in:
yun
2026-09-19 01:31:34 +08:00
parent 00eba5cc75
commit 407fc49e0c
20 changed files with 1710 additions and 376 deletions
Regular → Executable
+78 -58
View File
@@ -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...)
}