Compare commits
5 Commits
master
...
feature/up
Author | SHA1 | Date | |
---|---|---|---|
ab78127317 | |||
28da213bb8 | |||
13d1ab6607 | |||
bb5d97f6eb | |||
ac5776f3f6 |
@ -1,68 +0,0 @@
|
||||
// Package define ...
|
||||
//
|
||||
// Description : define ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2025-04-12 20:57
|
||||
package define
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
networkUtil "git.zhangdeman.cn/zhangdeman/network/util"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/trace"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
Context *gin.Context // 继承 gin context
|
||||
Trace *trace.Runtime // trace 实例
|
||||
TraceID string
|
||||
RequestID string
|
||||
RequestTime time.Time
|
||||
}
|
||||
|
||||
// NewContext 创建context
|
||||
func NewContext(ginCtx *gin.Context) *Context {
|
||||
existCtx, exist := ginCtx.Get(CustomContextKey)
|
||||
if exist && existCtx != nil {
|
||||
if c, ok := existCtx.(*Context); ok {
|
||||
return c
|
||||
}
|
||||
}
|
||||
traceID := fmt.Sprintf(
|
||||
"%v-%v-%v-%v",
|
||||
time.Now().UnixNano()/1e6,
|
||||
strings.ReplaceAll(networkUtil.IP.GetHostIP(), ".", ""),
|
||||
strings.ReplaceAll(networkUtil.IP.GetRemoteIP(ginCtx.Request), ".", ""),
|
||||
wrapper.StringFromRandom(32, "").Md5().Value,
|
||||
)
|
||||
getRequestID := func(ctx *gin.Context, traceID string) string {
|
||||
requestID := ctx.GetHeader("X-Forward-Request-Id")
|
||||
if len(requestID) > 0 {
|
||||
return requestID
|
||||
}
|
||||
if len(traceID) > 0 {
|
||||
return traceID
|
||||
}
|
||||
return traceID
|
||||
}
|
||||
ctx := &Context{
|
||||
Context: ginCtx,
|
||||
Trace: trace.NewRuntime(traceID, 1),
|
||||
TraceID: traceID,
|
||||
RequestID: getRequestID(ginCtx, traceID),
|
||||
RequestTime: time.Now(),
|
||||
}
|
||||
httpHandleConfig := GetHttpHandleConfig()
|
||||
ginCtx.Set(CustomContextKey, ctx)
|
||||
ginCtx.Set(httpHandleConfig.TraceIDField, traceID)
|
||||
ginCtx.Set(httpHandleConfig.RequestIDField, ctx.RequestID)
|
||||
ginCtx.Set(httpHandleConfig.StartRequestTimeField, ctx.RequestTime.UnixMilli())
|
||||
return ctx
|
||||
}
|
@ -4,9 +4,9 @@
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2025-04-12 20:18
|
||||
// Date : 2025-03-10 14:38
|
||||
package define
|
||||
|
||||
const (
|
||||
CustomContextKey = "_CUSTOM_CONTEXT" // 自定义context
|
||||
GinWrapperContextKey = "GIN_WRAPPER_CONTEXT"
|
||||
)
|
34
go.mod
34
go.mod
@ -2,18 +2,20 @@ module git.zhangdeman.cn/zhangdeman/gin
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.2
|
||||
toolchain go1.24.0
|
||||
|
||||
require (
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250220105101-71d6db967dc5
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250328040304-7e4a6f9f148c
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8
|
||||
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20250207091724-ca151fbc1f06
|
||||
git.zhangdeman.cn/zhangdeman/logger v0.0.0-20241125083316-eab7bab9d7ad
|
||||
git.zhangdeman.cn/zhangdeman/network v0.0.0-20230925112156-f0eb86dd2442
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740
|
||||
git.zhangdeman.cn/zhangdeman/trace v0.0.0-20231220041950-807f3d74a6fa
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250124091620-c757e551a8c9
|
||||
github.com/gin-contrib/pprof v1.5.2
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-playground/validator/v10 v10.26.0
|
||||
github.com/go-playground/validator/v10 v10.25.0
|
||||
github.com/mcuadros/go-defaults v1.2.0
|
||||
github.com/sbabiv/xml2map v1.2.1
|
||||
go.uber.org/zap v1.27.0
|
||||
@ -23,19 +25,17 @@ require (
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20230731062340-983985c12eda // indirect
|
||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20241101082529-28a6c68e38a4 // indirect
|
||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect
|
||||
git.zhangdeman.cn/zhangdeman/trace v0.0.0-20250412104923-c1ecb1bfe8d5 // indirect
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect
|
||||
git.zhangdeman.cn/zhangdeman/websocket v0.0.0-20241125101541-c5ea194c9c1e // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
|
||||
github.com/bytedance/sonic v1.13.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/bytedance/sonic v1.12.9 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.3 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/pprof v1.5.2 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
@ -59,7 +59,7 @@ require (
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mozillazg/go-pinyin v0.20.0 // indirect
|
||||
github.com/mssola/user_agent v0.6.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/swaggo/files v1.0.1 // indirect
|
||||
@ -71,13 +71,13 @@ require (
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.16.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/arch v0.14.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/tools v0.30.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
48
go.sum
48
go.sum
@ -1,15 +1,7 @@
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250219142545-bd7f6d2cfd99 h1:VYwbWsMcgQ7yWAGHB2v8Zbhh/5NIcQUq3yxay09zjkY=
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250219142545-bd7f6d2cfd99/go.mod h1:oNTwnepzW09RNfIQCpgmbiayTKLvGx2XP92esfkxv98=
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250220082250-6987b4829bf6 h1:C8otP/n4SPc8hQQxd9jOnPxb24l0KMhTNpxWtwz20js=
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250220082250-6987b4829bf6/go.mod h1:oNTwnepzW09RNfIQCpgmbiayTKLvGx2XP92esfkxv98=
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250220095851-22d937a4b1cb h1:E+KXP29m18dNfyVU8zBIBAEqE7aspLqFHa1bOnIMdq4=
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250220095851-22d937a4b1cb/go.mod h1:oNTwnepzW09RNfIQCpgmbiayTKLvGx2XP92esfkxv98=
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250220105101-71d6db967dc5 h1:UV2+nD9HQLbRt+vY98gwPtkd+M8fbfffl7nb4Mkymmc=
|
||||
git.zhangdeman.cn/gateway/api-doc v0.0.0-20250220105101-71d6db967dc5/go.mod h1:oNTwnepzW09RNfIQCpgmbiayTKLvGx2XP92esfkxv98=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250215141718-8232f587a6ea h1:6b9bfq44ewsXGVOkyZ+DQ4dNaKtmNsdHOFQxHUdEQrY=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250215141718-8232f587a6ea/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250328040304-7e4a6f9f148c h1:cl3gQGXQpJ8ugDs0C/hQLfcvF4lGBm5BeABLvROFDoM=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250328040304-7e4a6f9f148c/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8 h1:VEifPc+vkpEQoX9rj7zxmT1m+IA81XjOxe7+Z1aqWNM=
|
||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20230731062340-983985c12eda h1:bMD6r9gjRy7cO+T4zRQVYAesgIblBdTnhzT1vN5wjvI=
|
||||
git.zhangdeman.cn/zhangdeman/easylock v0.0.0-20230731062340-983985c12eda/go.mod h1:dT0rmHcJ9Z9IqWeMIt7YzR88nKkNV2V3dfG0j9Q6lK0=
|
||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20241101082529-28a6c68e38a4 h1:s6d4b6yY+NaK1AzoBD1pxqsuygEHQz0Oie86c45geDw=
|
||||
@ -24,33 +16,25 @@ git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 h1:gUDlQ
|
||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0/go.mod h1:VHb9qmhaPDAQDcS6vUiDCamYjZ4R5lD1XtVsh55KsMI=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd h1:q7GG14qgXKB4MEXQFOe7/UYebsqMfPaSX80TcPdOosI=
|
||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd/go.mod h1:+D6uPSljwHywjVY5WSBY4TRVMj26TN5f5cFGEYMldjs=
|
||||
git.zhangdeman.cn/zhangdeman/trace v0.0.0-20250412104923-c1ecb1bfe8d5 h1:dD1Q/MIrRmIhKqfYPH+y167ca9CKwTPuQt3c1hXWGJ8=
|
||||
git.zhangdeman.cn/zhangdeman/trace v0.0.0-20250412104923-c1ecb1bfe8d5/go.mod h1:PB486NC82nuvn5yi+U2i48ogX/9EAETWAHd8O9TwY9k=
|
||||
git.zhangdeman.cn/zhangdeman/trace v0.0.0-20231220041950-807f3d74a6fa h1:2bZ9VmQF0pIZ+scnN3UuGoXjjKhccnwfIL779QGZArY=
|
||||
git.zhangdeman.cn/zhangdeman/trace v0.0.0-20231220041950-807f3d74a6fa/go.mod h1:Bta0kzamTWqBIcc6robGAl/iRuyCFbzy45VGbG8L+7Y=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e h1:Q973S6CcWr1ICZhFI1STFOJ+KUImCl2BaIXm6YppBqI=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI=
|
||||
git.zhangdeman.cn/zhangdeman/websocket v0.0.0-20241125101541-c5ea194c9c1e h1:YE2Gi+M03UDImIpWa3I7jzSesyfu2RL8x/4ONs5v0oE=
|
||||
git.zhangdeman.cn/zhangdeman/websocket v0.0.0-20241125101541-c5ea194c9c1e/go.mod h1:L/7JugxKZL3JP9JP/XDvPAPz0FQXG1u181Su1+u/d1c=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250124091620-c757e551a8c9 h1:yF770WIDNwyiKL0nwmBGmjZvNCLXtHQL4xJyffPjTMU=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250124091620-c757e551a8c9/go.mod h1:I76wxEsWq7KnMQ84elpwTjEqq4I49QFw60tp5h7iGBs=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740 h1:zPUoylfJTbc0EcxW+NEzOTBmoeFZ2I/rLFBnEzxb4Wk=
|
||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740/go.mod h1:1ct92dbVc49pmXusA/iGfcQUJzcYmJ+cjAhgc3sDv1I=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
|
||||
github.com/bytedance/sonic v1.12.9 h1:Od1BvK55NnewtGaJsTDeAOSnLVO2BTSLOe0+ooKokmQ=
|
||||
github.com/bytedance/sonic v1.12.9/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0=
|
||||
github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
@ -67,8 +51,6 @@ github.com/gin-contrib/pprof v1.5.2 h1:Kcq5W2bA2PBcVtF0MqkQjpvCpwJr+pd7zxcQh2csg
|
||||
github.com/gin-contrib/pprof v1.5.2/go.mod h1:a1W4CDXwAPm2zql2AKdnT7OVCJdV/oFPhJXVOrDs5Ns=
|
||||
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
@ -89,8 +71,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-webtools/knife4go v1.0.4 h1:p32SApmM0sx2/Y5p0QfeaGv5KD96R1mj2CaHdyH8jy8=
|
||||
github.com/go-webtools/knife4go v1.0.4/go.mod h1:trOlXN1tqBJ7R44sHON3exGvzCwjbsVriIHEenry3d8=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
@ -109,8 +89,6 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
@ -150,8 +128,6 @@ github.com/mssola/user_agent v0.6.0/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRG
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@ -200,14 +176,10 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
|
||||
golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
@ -217,8 +189,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
@ -232,8 +202,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@ -243,8 +211,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
@ -255,8 +221,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IV
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
200
request/context.go
Normal file
200
request/context.go
Normal file
@ -0,0 +1,200 @@
|
||||
// Package request ...
|
||||
//
|
||||
// Description : request ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2025-02-28 11:45
|
||||
package request
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
networkUtil "git.zhangdeman.cn/zhangdeman/network/util"
|
||||
"git.zhangdeman.cn/zhangdeman/trace"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"github.com/gin-gonic/gin"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// getTraceID 生成traceID
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 23:12 2022/6/25
|
||||
func getTraceID(ctx *gin.Context) string {
|
||||
hostname, _ := os.Hostname()
|
||||
if hostname != "" {
|
||||
hostname = "unknown"
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"%v-%v-%v-%v-%v",
|
||||
time.Now().UnixNano()/1e6,
|
||||
strings.ReplaceAll(networkUtil.IP.GetHostIP(), ".", ""),
|
||||
strings.ReplaceAll(hostname, ".", ""),
|
||||
strings.ReplaceAll(networkUtil.IP.GetRemoteIP(ctx.Request), ".", ""),
|
||||
wrapper.StringFromRandom(32, "").Md5().Value,
|
||||
)
|
||||
}
|
||||
|
||||
// getRequestID 生成requestID
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 23:12 2022/6/25
|
||||
func getRequestID(ctx *gin.Context, traceID string) string {
|
||||
requestID := ctx.GetHeader("X-Forward-Request-Id")
|
||||
if len(requestID) > 0 {
|
||||
return requestID
|
||||
}
|
||||
if len(traceID) > 0 {
|
||||
return traceID
|
||||
}
|
||||
return getTraceID(ctx)
|
||||
}
|
||||
|
||||
// NewContext 获取context实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:01 2025/2/28
|
||||
func NewContext(ginContext *gin.Context) *Context {
|
||||
// 生成traceID
|
||||
traceID := getRequestID(ginContext, "")
|
||||
hostname, _ := os.Hostname()
|
||||
return &Context{
|
||||
Context: ginContext,
|
||||
StartRequestTime: time.Now(),
|
||||
FinishRequestTime: time.Unix(0, 0),
|
||||
HandlerAfterResponse: make([]gin.HandlerFunc, 0),
|
||||
customData: make(map[string]any),
|
||||
Hostname: hostname,
|
||||
HostIp: networkUtil.IP.GetHostIP(),
|
||||
customLock: &sync.RWMutex{},
|
||||
TraceID: traceID,
|
||||
Trace: trace.NewRuntime(traceID, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// Context 请求上下文信息, 对 ctx *gin.Context的二次包装
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:45 2025/2/28
|
||||
type Context struct {
|
||||
*gin.Context `json:"-"`
|
||||
StartRequestTime time.Time `json:"start_request_time"` // 开始请求时间(全局)
|
||||
FinishRequestTime time.Time `json:"finish_request_time"` // 结束请求时间(全局)
|
||||
TraceID string `json:"trace_id"` // 请求trace_id
|
||||
ParentAppName string `json:"parent_app_name"` // 父级应用名称
|
||||
HandlerAfterResponse []gin.HandlerFunc `json:"-"` // 响应数据之后需要执行的逻辑
|
||||
Hostname string `json:"hostname"` // 服务器名称
|
||||
HostIp string `json:"host_ip"` // 服务器IP
|
||||
customData map[string]any `json:"-"` // 业务上下文自定义数据, 可以合 ginCtx.Value 作区分
|
||||
customLock *sync.RWMutex `json:"-"` // 数据锁
|
||||
Trace *trace.Runtime `json:"-"` // 追踪实例
|
||||
}
|
||||
|
||||
// SetCustom 设置数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:58 2025/2/28
|
||||
func (ctx *Context) SetCustom(key string, val any) {
|
||||
ctx.customLock.Lock()
|
||||
defer ctx.customLock.Unlock()
|
||||
if nil == ctx.customData {
|
||||
ctx.customData = make(map[string]any)
|
||||
}
|
||||
ctx.Set(key, val)
|
||||
ctx.customData[key] = val
|
||||
}
|
||||
|
||||
// customDataValue 获取customData
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:03 2025/2/28
|
||||
func (ctx *Context) customDataValue(key string) any {
|
||||
ctx.customLock.RLock()
|
||||
defer ctx.customLock.RUnlock()
|
||||
if val, exist := ctx.customData[key]; exist {
|
||||
return val
|
||||
} else {
|
||||
return ctx.Value(key)
|
||||
}
|
||||
}
|
||||
|
||||
// customDataExist 判断
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:04 2025/2/28
|
||||
func (ctx *Context) customDataExist(key string) any {
|
||||
ctx.customLock.RLock()
|
||||
defer ctx.customLock.RUnlock()
|
||||
_, exist := ctx.customData[key]
|
||||
return exist
|
||||
}
|
||||
|
||||
// customDataAppend 向数组数据中追加元素
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:07 2025/2/28
|
||||
func (ctx *Context) customDataAppend(key string, appendValue any) {
|
||||
ctx.customLock.Lock()
|
||||
defer ctx.customLock.Unlock()
|
||||
val, exist := ctx.customData[key]
|
||||
if !exist || nil == val {
|
||||
ctx.customData[key] = []any{appendValue}
|
||||
return
|
||||
}
|
||||
if valArr, ok := val.([]any); ok {
|
||||
valArr = append(valArr, appendValue)
|
||||
ctx.customData[key] = valArr
|
||||
}
|
||||
// 非数组, 忽略追加行为
|
||||
}
|
||||
|
||||
// customDataAppendProperty 向一个map中追加/更新属性
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:11 2025/2/28
|
||||
func (ctx *Context) customDataAppendProperty(key string, appendKey string, appendValue any) {
|
||||
ctx.customLock.Lock()
|
||||
defer ctx.customLock.Unlock()
|
||||
val, exist := ctx.customData[key]
|
||||
if !exist || nil == val {
|
||||
ctx.customData[key] = map[string]any{
|
||||
appendKey: appendValue,
|
||||
}
|
||||
return
|
||||
}
|
||||
if valMap, ok := val.(map[string]any); ok {
|
||||
valMap[appendKey] = appendValue
|
||||
ctx.customData[key] = valMap
|
||||
}
|
||||
// 非map, 忽略追加行为
|
||||
}
|
||||
|
||||
// TraceStart 开始监控
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:24 2025/2/28
|
||||
func (ctx *Context) TraceStart(action string, actionData map[string]any) int {
|
||||
return ctx.Trace.StartBehavior(action, actionData)
|
||||
}
|
||||
|
||||
// TraceEnd 完成监控
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:24 2025/2/28
|
||||
func (ctx *Context) TraceEnd(behaviorID int, endData map[string]any) {
|
||||
ctx.Trace.FinishBehavior(behaviorID, endData)
|
||||
}
|
@ -8,15 +8,12 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/trace"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/gin/define"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/request/parse_body"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -120,8 +117,8 @@ func (wh *wrapperHandle) GetContentType(ctx *gin.Context, defaultVal string) str
|
||||
if nil == ctx {
|
||||
return defaultVal
|
||||
}
|
||||
contentType := strings.ToLower(ctx.ContentType())
|
||||
return wrapper.TernaryOperator.String(len(contentType) > 0, wrapper.String(contentType), wrapper.String(defaultVal)).Value()
|
||||
contentTypeVal := strings.ToLower(ctx.ContentType())
|
||||
return wrapper.TernaryOperator.String(len(contentTypeVal) > 0, wrapper.String(contentTypeVal), wrapper.String(defaultVal)).Value()
|
||||
}
|
||||
|
||||
// GetDomain 获取请求Domain
|
||||
@ -274,6 +271,40 @@ func (wh *wrapperHandle) ParseCookie(ctx *gin.Context) map[string]string {
|
||||
return cookieData
|
||||
}
|
||||
|
||||
// Copy 复制context
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:00 2025/2/28
|
||||
//
|
||||
// - ctx *gin.Context : 基于哪一个context复制context
|
||||
// - isCopyContextValue bool : 是否继承父级ctx的自定义value
|
||||
func (wh *wrapperHandle) Copy(ctx *gin.Context, isCopyContextValue bool, excludeKeyList []string) *gin.Context {
|
||||
if nil == ctx {
|
||||
return nil
|
||||
}
|
||||
newContext := ctx.Copy()
|
||||
excludeKeyTable := map[string]bool{}
|
||||
for _, excludeKey := range excludeKeyList {
|
||||
excludeKeyTable[excludeKey] = true
|
||||
}
|
||||
if isCopyContextValue {
|
||||
// 上下文设置的业务数据值也继承下来, TODO: 并发读写此处可能panic
|
||||
for k, v := range newContext.Keys {
|
||||
if !excludeKeyTable[k] {
|
||||
// 没有指定不继承
|
||||
ctx.Set(k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置父级context
|
||||
ctx.Set("parent_context", ctx)
|
||||
if nil == ctx.Value("root_context") {
|
||||
ctx.Set("root_context", ctx)
|
||||
}
|
||||
return newContext
|
||||
}
|
||||
|
||||
// GetLogicAfterResponse ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
@ -296,12 +327,20 @@ func (wh *wrapperHandle) GetLogicAfterResponse(ctx *gin.Context) *define.LogicAf
|
||||
return l.(*define.LogicAfterResponse)
|
||||
}
|
||||
|
||||
// GetCustomContext 获取自定义context
|
||||
func (wh *wrapperHandle) GetCustomContext(ctx *gin.Context) *define.Context {
|
||||
return define.NewContext(ctx)
|
||||
}
|
||||
|
||||
// GetTraceInstance 获取trace实例
|
||||
func (wh *wrapperHandle) GetTraceInstance(ctx *gin.Context) *trace.Runtime {
|
||||
return define.NewContext(ctx).Trace
|
||||
// GetGinWrapperContext 获取包装之后context
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:41 2025/3/10
|
||||
func (wh *wrapperHandle) GetGinWrapperContext(ctx *gin.Context) *Context {
|
||||
if nil == ctx {
|
||||
return nil
|
||||
}
|
||||
if val, exist := ctx.Get(define.GinWrapperContextKey); !exist || nil == val {
|
||||
newCtx := NewContext(ctx)
|
||||
newCtx.SetCustom(define.GinWrapperContextKey, newCtx)
|
||||
return newCtx
|
||||
} else {
|
||||
return val.(*Context)
|
||||
}
|
||||
}
|
||||
|
@ -69,9 +69,9 @@ func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, n
|
||||
needRegister = false
|
||||
return
|
||||
}
|
||||
// 第一个参数必须是 *gin.Context 或者 *define.Context
|
||||
paramOne := methodType.In(1).String()
|
||||
if paramOne != GinContextType && paramOne != CustomContextType {
|
||||
// 第一个参数必须是 *gin.Context
|
||||
firstParamStr := methodType.In(1).String()
|
||||
if firstParamStr != GinContextType && firstParamStr != GinWrapperContextType {
|
||||
needRegister = false
|
||||
return
|
||||
}
|
||||
@ -106,8 +106,9 @@ func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, n
|
||||
return
|
||||
}
|
||||
}
|
||||
// 是否gin包装后的context
|
||||
cfg.IsGinWrapperContext = firstParamStr == GinWrapperContextType
|
||||
// 解析meta信息
|
||||
cfg.CtxType = paramOne
|
||||
cfg.Path = metaField.Tag.Get(TagNamePath)
|
||||
cfg.RequestMethod = metaField.Tag.Get(TagNameMethod)
|
||||
cfg.Desc = metaField.Tag.Get(TagNameDesc)
|
||||
|
@ -15,7 +15,7 @@ const (
|
||||
PrefixFuncName = "RouterPrefix" // 路由前缀函数名称
|
||||
MiddlewareFuncName = "RouterMiddleware" // 路由中间件函数名称
|
||||
GinContextType = "*gin.Context" // gin context 类型名称
|
||||
CustomContextType = "*define.Context" // custom context 类型名称
|
||||
GinWrapperContextType = "*request.Context" // gin context 类型名称
|
||||
ErrorType = "error" // error类型
|
||||
ErrorInterfaceFuncName = "Error" // error接口需要实现的方法名称
|
||||
)
|
||||
@ -37,16 +37,16 @@ const (
|
||||
//
|
||||
// Date : 15:41 2024/7/21
|
||||
type UriConfig struct {
|
||||
Path string `json:"path"` // 接口路由, 必须配置
|
||||
RequestMethod string `json:"request_method"` // 接口请求方法, 必须配置
|
||||
TagList []string `json:"tag_list"` // 接口分组
|
||||
Desc string `json:"desc"` // 接口描述
|
||||
OutputStrict bool `json:"output_strict"` // 接口是否为严格模式 : 不配置,可返回任意类型, 配置, 必须返回结构体或者map
|
||||
CtxType string `json:"ctx_type"` // ctx参数类型
|
||||
FormDataType reflect.Type `json:"-"` // 表单数据类型
|
||||
ResultDataType reflect.Type `json:"-"` // 返回值数据类型
|
||||
ApiStructValue reflect.Value `json:"-"` // 逻辑函数所属结构体取值
|
||||
ApiLogicFunc reflect.Method `json:"-"` // 自定义的接口逻辑
|
||||
Path string `json:"path"` // 接口路由, 必须配置
|
||||
RequestMethod string `json:"request_method"` // 接口请求方法, 必须配置
|
||||
TagList []string `json:"tag_list"` // 接口分组
|
||||
Desc string `json:"desc"` // 接口描述
|
||||
OutputStrict bool `json:"output_strict"` // 接口是否为严格模式 : 不配置,可返回任意类型, 配置, 必须返回结构体或者map
|
||||
FormDataType reflect.Type `json:"-"` // 表单数据类型
|
||||
ResultDataType reflect.Type `json:"-"` // 返回值数据类型
|
||||
ApiStructValue reflect.Value `json:"-"` // 逻辑函数所属结构体取值
|
||||
ApiLogicFunc reflect.Method `json:"-"` // 自定义的接口逻辑
|
||||
IsGinWrapperContext bool `json:"is_gin_wrapper_context"` // 是否gin包装后的context
|
||||
}
|
||||
|
||||
// UriParam 接口参数配置
|
||||
|
@ -8,15 +8,13 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/exception"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/define"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/request"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// RequestHandler 获取请求处理方法
|
||||
@ -60,12 +58,7 @@ func RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
|
||||
ctx.Set(define.LogicAfterResponseKey, logicAfterResponse)
|
||||
defer func() {
|
||||
go func() {
|
||||
// 执行响应之后的相关逻辑
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
||||
}
|
||||
}()
|
||||
defer recover()
|
||||
if isSuccess {
|
||||
for _, itemFunc := range logicAfterResponse.SuccessHookFuncList {
|
||||
if nil != itemFunc {
|
||||
@ -86,14 +79,14 @@ func RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
|
||||
if uriCfg.FormDataType.Kind() != reflect.Ptr {
|
||||
inputValue = inputValue.Elem()
|
||||
}
|
||||
var firstParam reflect.Value
|
||||
if uriCfg.CtxType == CustomContextType {
|
||||
customCtx := ctx.MustGet(define.CustomContextKey)
|
||||
firstParam = reflect.ValueOf(customCtx)
|
||||
} else {
|
||||
firstParam = reflect.ValueOf(ctx)
|
||||
ginWrapperContext := request.NewContext(ctx)
|
||||
// wrapper context 设置到 gin context
|
||||
ginWrapperContext.Set(define.GinWrapperContextKey, ginWrapperContext)
|
||||
ctxReflect := reflect.ValueOf(ctx)
|
||||
if uriCfg.IsGinWrapperContext {
|
||||
ctxReflect = reflect.ValueOf(ginWrapperContext)
|
||||
}
|
||||
resList := uriCfg.ApiLogicFunc.Func.Call([]reflect.Value{uriCfg.ApiStructValue, firstParam, inputValue})
|
||||
resList := uriCfg.ApiLogicFunc.Func.Call([]reflect.Value{uriCfg.ApiStructValue, ctxReflect, inputValue})
|
||||
if resList[1].IsNil() {
|
||||
// 请求成功
|
||||
isSuccess = true
|
||||
@ -101,7 +94,7 @@ func RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
// 请求失败
|
||||
if ok = errors.As(resList[1].Interface().(error), &e); ok {
|
||||
if e, ok = resList[1].Interface().(exception.IException); ok {
|
||||
// 本身就是exception.IException
|
||||
} else if err, ok = resList[1].Interface().(error); ok {
|
||||
e = exception.NewFromError(-1, err)
|
||||
|
@ -8,11 +8,10 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
apiDocDefine "git.zhangdeman.cn/gateway/api-doc/define"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/middleware"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SetServerOptionFunc func(so *serverOption)
|
||||
@ -30,6 +29,7 @@ type serverOption struct {
|
||||
serverInfo *apiDocDefine.Info // 服务器信息
|
||||
serverList []*apiDocDefine.ServerItem // 服务器环境列表
|
||||
enablePprof bool // 启用pprof
|
||||
enableRequestInit bool // 初始化请求,生成trace_id 设置请求时间等
|
||||
enableCors bool // 启动跨域支持
|
||||
loggerCfg *middleware.AccessConfig // 日志配置
|
||||
}
|
||||
@ -126,6 +126,17 @@ func WithPprofEnable() SetServerOptionFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableRequestInit 全局配置初始化
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:56 2025/2/22
|
||||
func WithEnableRequestInit() SetServerOptionFunc {
|
||||
return func(so *serverOption) {
|
||||
so.enableRequestInit = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableCors 启用全局跨域
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
|
214
router/register.go
Normal file
214
router/register.go
Normal file
@ -0,0 +1,214 @@
|
||||
// Package router ...
|
||||
//
|
||||
// Description : router ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-07-20 21:39
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.zhangdeman.cn/zhangdeman/exception"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/middleware"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/request"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/response"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
Debug = false // 是否开启DEBUG
|
||||
ginRouter = gin.Default()
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
|
||||
// Register 注册路由
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 21:40 2024/7/20
|
||||
func Register(port int, controllerList ...any) error {
|
||||
for _, itemController := range controllerList {
|
||||
if nil == itemController {
|
||||
// 忽略空指针
|
||||
continue
|
||||
}
|
||||
parseController(itemController)
|
||||
}
|
||||
return ginRouter.Run(fmt.Sprintf(":%d", port))
|
||||
}
|
||||
|
||||
// parseController 解析controller
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 22:10 2024/7/20
|
||||
func parseController(controller any) {
|
||||
controllerType := reflect.TypeOf(controller)
|
||||
controllerValue := reflect.ValueOf(controller)
|
||||
routerPrefix := "/"
|
||||
// 解析路由前缀函数
|
||||
// routerPrefix 不能有任何入参, 并且只能有一个返回值,
|
||||
// 返回值类型为字符串, 为具体路由前缀
|
||||
routerPrefixFunc, routerPrefixFuncExist := controllerType.MethodByName(PrefixFuncName)
|
||||
if routerPrefixFuncExist {
|
||||
routerPrefixFuncType := routerPrefixFunc.Type
|
||||
if routerPrefixFuncType.NumIn() == 1 && // 无任何入参, 正在没有如何入参情况下, 第一个参数是结构体指针
|
||||
routerPrefixFuncType.NumOut() == 1 && // 只能有一个返回值
|
||||
routerPrefixFuncType.Out(0).Kind() == reflect.String { // 返回值必须是字符串
|
||||
routerPrefix = routerPrefixFunc.Func.Call([]reflect.Value{controllerValue})[0].String()
|
||||
}
|
||||
}
|
||||
// 请求组的中间件
|
||||
middlewareList := make([]gin.HandlerFunc, 0)
|
||||
routerMiddlewareFunc, routerMiddlewareFuncExist := controllerType.MethodByName(MiddlewareFuncName)
|
||||
if routerMiddlewareFuncExist {
|
||||
routerMiddlewareFuncType := routerMiddlewareFunc.Type
|
||||
if routerMiddlewareFuncType.NumIn() == 1 && // 无需任何参数
|
||||
routerMiddlewareFuncType.NumOut() == 1 && // 只能有一个返回值
|
||||
routerMiddlewareFuncType.Out(0).String() == "[]gin.HandlerFunc" { // 返回值必须是gin.HandlerFunc
|
||||
res := routerMiddlewareFunc.Func.Call([]reflect.Value{controllerValue})
|
||||
if !res[0].IsNil() {
|
||||
middlewareList = res[0].Interface().([]gin.HandlerFunc)
|
||||
}
|
||||
}
|
||||
}
|
||||
for funcIdx := 0; funcIdx < controllerType.NumMethod(); funcIdx++ {
|
||||
method := controllerType.Method(funcIdx)
|
||||
if method.Name == PrefixFuncName || method.Name == MiddlewareFuncName {
|
||||
continue
|
||||
}
|
||||
methodType := method.Type
|
||||
uriConfig, err := parseUriConfig(methodType, routerPrefix)
|
||||
if nil != err {
|
||||
debugLog("parseUriConfig error : %s -> %s", err.Error(), methodType.Kind().String())
|
||||
}
|
||||
if nil == uriConfig {
|
||||
continue
|
||||
}
|
||||
registerUri(uriConfig, controllerValue.Method(funcIdx), middlewareList)
|
||||
}
|
||||
}
|
||||
|
||||
// parseUriConfig 解析Uri配置
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:40 2024/7/21
|
||||
func parseUriConfig(methodType reflect.Type, routerPrefix string) (*UriConfig, error) {
|
||||
if methodType.NumIn() != 3 || // 结构体指针 + 两个参数
|
||||
methodType.NumOut() != 2 { // 两个返回值
|
||||
return nil, nil
|
||||
}
|
||||
// 接口logic共计两个参数. 两个返回值, 格式 : func(ctx *gin.Context, formData any[组合Meta]) (any[response], error)
|
||||
|
||||
// 解析第一个参数是 *gin.Context / 或者包装后的 request.Context
|
||||
firstParamStr := methodType.In(1).String()
|
||||
if firstParamStr != "*gin.Context" && firstParamStr != "*request.Context" {
|
||||
return nil, nil
|
||||
}
|
||||
// 解析第二个参数是组合Meta的form表单
|
||||
formType := methodType.In(2)
|
||||
if formType.Kind() == reflect.Ptr {
|
||||
formType = methodType.In(2).Elem()
|
||||
}
|
||||
metaField, metaFieldExist := formType.FieldByName(FieldNameMeta)
|
||||
if !metaFieldExist {
|
||||
return nil, nil
|
||||
}
|
||||
uriConfig := &UriConfig{
|
||||
Path: strings.TrimRight(routerPrefix, "/") + "/" + strings.TrimLeft(metaField.Tag.Get(TagNamePath), "/"),
|
||||
RequestMethod: strings.ToUpper(metaField.Tag.Get(TagNameMethod)),
|
||||
TagList: strings.Split(metaField.Tag.Get(TagNameUriTag), "|"),
|
||||
Desc: metaField.Tag.Get(TagNameDesc),
|
||||
OutputStrict: wrapper.ArrayType([]string{"", "true"}).Has(strings.ToLower(metaField.Tag.Get(TagNameOutputStrict))) >= 0,
|
||||
FormDataType: methodType.In(2).Elem(),
|
||||
}
|
||||
// 校验 FormDataType
|
||||
for fieldIdx := 0; fieldIdx < uriConfig.FormDataType.NumField(); fieldIdx++ {
|
||||
if uriConfig.FormDataType.Field(fieldIdx).Type.Kind() == reflect.Interface {
|
||||
panic("request param set type `interface` is not allowed")
|
||||
}
|
||||
}
|
||||
return uriConfig, nil
|
||||
}
|
||||
|
||||
// registerUri 注册路由
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:00 2024/7/21
|
||||
func registerUri(uriConfig *UriConfig, methodValue reflect.Value, middlewareList []gin.HandlerFunc) {
|
||||
if nil == middlewareList {
|
||||
middlewareList = make([]gin.HandlerFunc, 0)
|
||||
}
|
||||
handlerFunc := func(ctx *gin.Context) {
|
||||
formDataReceiver := reflect.New(uriConfig.FormDataType)
|
||||
if err := request.Form.Parse(ctx, formDataReceiver.Interface()); nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
returnValue := methodValue.Call([]reflect.Value{reflect.ValueOf(ctx), formDataReceiver})
|
||||
businessData := returnValue[0].Interface()
|
||||
errData := returnValue[1]
|
||||
if errData.IsNil() {
|
||||
response.Success(ctx, businessData)
|
||||
return
|
||||
}
|
||||
err := errData.Interface()
|
||||
if e, ok := err.(exception.IException); ok {
|
||||
response.SendWithException(ctx, e, map[string]any{"business_data": businessData})
|
||||
return
|
||||
} else {
|
||||
response.SendWithException(ctx, exception.NewFromError(-1, errData.Interface().(error)), map[string]any{"business_data": businessData})
|
||||
return
|
||||
}
|
||||
}
|
||||
middlewareList = append(middlewareList, handlerFunc)
|
||||
middlewareList = append([]gin.HandlerFunc{
|
||||
middleware.InitRequest(),
|
||||
}, middlewareList...)
|
||||
switch uriConfig.RequestMethod {
|
||||
case http.MethodGet:
|
||||
ginRouter.GET(uriConfig.Path, middlewareList...)
|
||||
case http.MethodHead:
|
||||
ginRouter.HEAD(uriConfig.Path, middlewareList...)
|
||||
case http.MethodPost:
|
||||
ginRouter.PUT(uriConfig.Path, middlewareList...)
|
||||
case http.MethodPut:
|
||||
ginRouter.PUT(uriConfig.Path, middlewareList...)
|
||||
case http.MethodPatch:
|
||||
ginRouter.PATCH(uriConfig.Path, middlewareList...)
|
||||
case http.MethodDelete:
|
||||
ginRouter.DELETE(uriConfig.Path, middlewareList...)
|
||||
case http.MethodConnect:
|
||||
ginRouter.Handle(http.MethodConnect, uriConfig.Path, middlewareList...)
|
||||
case http.MethodOptions:
|
||||
ginRouter.OPTIONS(uriConfig.Path, middlewareList...)
|
||||
case http.MethodTrace:
|
||||
ginRouter.Handle(http.MethodTrace, uriConfig.Path, middlewareList...)
|
||||
case "ANY":
|
||||
ginRouter.Any(uriConfig.Path, middlewareList...)
|
||||
default:
|
||||
panic(uriConfig.Path + " : " + uriConfig.RequestMethod + " is not support")
|
||||
}
|
||||
}
|
||||
|
||||
// debugLog ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:32 2024/7/21
|
||||
func debugLog(format string, valList ...any) {
|
||||
if !Debug {
|
||||
return
|
||||
}
|
||||
fmt.Printf("[DEBUG] "+format+"\n", valList...)
|
||||
}
|
47
router/register_test.go
Normal file
47
router/register_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
// Package router ...
|
||||
//
|
||||
// Description : router ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2024-07-20 23:24
|
||||
package router
|
||||
|
||||
import (
|
||||
"git.zhangdeman.cn/zhangdeman/gin/request"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type TestController struct{}
|
||||
|
||||
func (t TestController) Logic(ctx *request.Context, formData *TestForm) (TestOut, error) {
|
||||
return TestOut{
|
||||
FormData: formData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type TestOut struct {
|
||||
Age int `json:"age" form:"age" binding:"min=20" err_msg:"年龄不能小于20"`
|
||||
Name string `json:"name" form:"name"`
|
||||
Test *Test `json:"test" form:"test"`
|
||||
Num *int64 `json:"num" form:"num"`
|
||||
FormData *TestForm `json:"form_data" form:"form_data"`
|
||||
}
|
||||
|
||||
type TestForm struct {
|
||||
Meta `tag:"测试表单" path:"/a/b/c/d" desc:"测试接口" method:"GET"`
|
||||
Age int `json:"age" form:"age" binding:"min=20" err_msg:"年龄不能小于20"`
|
||||
Name string `json:"name" form:"name"`
|
||||
Test *Test `json:"test" form:"test"`
|
||||
Num *int64 `json:"num" form:"num"`
|
||||
}
|
||||
type Test struct {
|
||||
L string `json:"l"`
|
||||
}
|
||||
|
||||
func Test_parseController(t *testing.T) {
|
||||
SetValidateErrTag("err_msg")
|
||||
s := NewServer(8888, nil)
|
||||
s.Group("test", nil, TestController{})
|
||||
s.Start()
|
||||
}
|
@ -9,16 +9,13 @@ package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/gin/define"
|
||||
|
||||
apiDoc "git.zhangdeman.cn/gateway/api-doc"
|
||||
"git.zhangdeman.cn/zhangdeman/consts"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/middleware"
|
||||
"git.zhangdeman.cn/zhangdeman/gin/middleware/request_cors"
|
||||
"github.com/gin-contrib/pprof"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
apiDocDefine "git.zhangdeman.cn/gateway/api-doc/define"
|
||||
"github.com/gin-gonic/gin"
|
||||
@ -73,14 +70,10 @@ func NewServer(port int, optionList ...SetServerOptionFunc) *server {
|
||||
}
|
||||
option := newServerOption(port, optionList...)
|
||||
globalMiddlewareList := make([]gin.HandlerFunc, 0)
|
||||
// CustomContext 必须在第一个, 并且进行初始化
|
||||
globalMiddlewareList = append(
|
||||
globalMiddlewareList,
|
||||
func(ctx *gin.Context) {
|
||||
// 初始化上下文以及基础信息
|
||||
_ = define.NewContext(ctx)
|
||||
},
|
||||
)
|
||||
if option.enableRequestInit {
|
||||
// 初始化请求中间件
|
||||
globalMiddlewareList = append(globalMiddlewareList, middleware.InitRequest())
|
||||
}
|
||||
if nil != option.loggerCfg {
|
||||
// 请求日志记录中间件
|
||||
globalMiddlewareList = append(globalMiddlewareList, middleware.LogRequest(option.loggerCfg))
|
||||
|
Loading…
x
Reference in New Issue
Block a user