优化方法的使用

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
Executable
+128
View File
@@ -0,0 +1,128 @@
package ginx
// Package ginx 是 responsex 的 gin 适配层。
//
// 依赖隔离:本包只依赖 gin、responsex 核心与 langx,
// import 本包不会引入 go-zero / gorm。
//
// go-zero 的 trace 提取(OpenTelemetry span 里的 trace_id)需要另外按需 import:
//
// import _ "code.yun.ink/pkg/responsex/gozerotrace"
//
// import 路径:code.yun.ink/pkg/responsex/gin
import (
"context"
"code.yun.ink/pkg/responsex"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/yuninks/langx"
)
// traceIDCtxKey 是 gin 侧约定的 trace_id key(c.Set / c.Get 使用)
const traceIDCtxKey = "trace_id"
// Middleware 桥接 gin 与 responsex 核心:
//
// 1. 把 gin 的 trace_id 写进标准 context(核心包据此输出 trace_id);
// 2. 按 Accept-Language 写入语言(核心包据此翻译文案)。
//
// 为什么需要它:gin 的 c.Value() 读不到 c.Set() 存的值,而 responsex 核心只认标准
// context,没有中间件时 trace_id 不会出现在响应里。
//
// r := gin.New()
// r.Use(ginx.Middleware())
//
// 业务侧只需像以前一样调用 c.Set("trace_id", id),响应会自动带上。
func Middleware(ops ...responsex.Option) gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request == nil {
c.Next()
return
}
responsex.InitOptions(ops...)
c.Request = c.Request.WithContext(bridgeCtx(c))
c.Next()
}
}
// bridgeCtx 由 gin.Context 构造标准 context(trace_id + 语言)
func bridgeCtx(c *gin.Context) context.Context {
ctx := context.Background()
if c.Request != nil {
ctx = c.Request.Context()
}
responsex.SetTraceKey(traceIDCtxKey)
// trace_id:优先 gin context,其次请求头
if v, ok := c.Get(traceIDCtxKey); ok {
if s, ok := v.(string); ok && s != "" {
uuid := uuid.New().String()
ctx = context.WithValue(ctx, traceIDCtxKey, uuid)
}
} else if val, ok := c.Get("trace_id"); ok {
ctx = context.WithValue(ctx, traceIDCtxKey, val)
} else if s := c.GetHeader("X-Request-Id"); s != "" {
ctx = context.WithValue(ctx, traceIDCtxKey, s)
} else {
ctx = context.WithValue(ctx, traceIDCtxKey, uuid.New().String())
}
// Accept-Language:核心包按此语言取译文
if lang := c.GetHeader("Accept-Language"); lang != "" {
ctx = langx.SetCtxLang(ctx, lang)
}
return ctx
}
// requestCtx 返回用于构造响应的 context。
// 在中间件建立的 ctx 基础上,于写响应前再同步一次 trace_id,
// 这样 handler 内部才调用 c.Set("trace_id", ...) 也能生效。
func requestCtx(c *gin.Context) context.Context {
if c.Request == nil {
return context.Background()
}
ctx := c.Request.Context()
if v, ok := c.Get(traceIDCtxKey); ok {
if s, ok := v.(string); ok && s != "" {
ctx = context.WithValue(ctx, traceIDCtxKey, s)
}
}
return ctx
}
func Error(c *gin.Context, err error, ops ...responsex.Option) {
responsex.Error(requestCtx(c), c.Writer, err, ops...)
}
func ErrorWithData(c *gin.Context, err error, data any, ops ...responsex.Option) {
responsex.ErrorWithData(requestCtx(c), c.Writer, err, data, ops...)
}
func ErrorStr(c *gin.Context, msg string, ops ...responsex.Option) {
responsex.ErrorStr(requestCtx(c), c.Writer, msg, ops...)
}
func Success(c *gin.Context, data any, ops ...responsex.Option) {
responsex.Success(requestCtx(c), c.Writer, data, ops...)
}
func SuccessWithPage(c *gin.Context, data any, page responsex.Pagination, ops ...responsex.Option) {
responsex.SuccessWithPage(requestCtx(c), c.Writer, data, &page, ops...)
}
func Custom(c *gin.Context, ops ...responsex.Option) {
responsex.ResponseCtx(requestCtx(c), c.Writer, ops...)
}
func MsgMapData(c *gin.Context, msgKey string, format map[string]string, data any, ops ...responsex.Option) {
responsex.FormatMessage(requestCtx(c), c.Writer, msgKey, format, data, ops...)
}
func MsgKV(c *gin.Context, msgKey string, k string, v string, ops ...responsex.Option) {
responsex.FormatMessage(requestCtx(c), c.Writer, msgKey, map[string]string{k: v}, nil, ops...)
}