diff --git a/go.mod b/go.mod index dde37b5..660bd30 100644 --- a/go.mod +++ b/go.mod @@ -7,21 +7,21 @@ toolchain go1.24.2 require ( git.zhangdeman.cn/zhangdeman/api-doc v1.0.3-0.20251013152001-868ee8955623 git.zhangdeman.cn/zhangdeman/consts v0.0.0-20260102134357-189dc7f57c1a - git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20251013092857-dcf591d4e8a8 + git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20251207071238-9aa24be3d708 git.zhangdeman.cn/zhangdeman/exception v0.0.0-20250510123912-a0d52fc093ab git.zhangdeman.cn/zhangdeman/graceful v0.0.0-20250529070945-92833db6f3a4 - git.zhangdeman.cn/zhangdeman/logger v0.0.0-20251031042950-416e962cbf3b - git.zhangdeman.cn/zhangdeman/network v0.0.0-20251013095944-5b89fff39bde + git.zhangdeman.cn/zhangdeman/logger v0.0.0-20251231045117-f05cb1e30afe + git.zhangdeman.cn/zhangdeman/network v0.0.0-20251220063845-8403861d36e5 git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20251013044511-86c1a4a3a9dd git.zhangdeman.cn/zhangdeman/trace v0.0.0-20251013092356-b7b9fb5f8a76 - git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e - git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20251014035305-c0ec06fa6dff + git.zhangdeman.cn/zhangdeman/util v0.0.0-20260103142706-1f6145405ec4 + git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20251225094759-09c64ba2541c github.com/gin-contrib/pprof v1.5.3 github.com/gin-gonic/gin v1.11.0 github.com/go-playground/validator/v10 v10.30.1 github.com/jedib0t/go-pretty/v6 v6.7.8 github.com/mcuadros/go-defaults v1.2.0 - go.uber.org/zap v1.27.0 + go.uber.org/zap v1.27.1 ) require ( @@ -38,6 +38,7 @@ require ( github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect github.com/gabriel-vasile/mimetype v1.4.12 // indirect github.com/gin-contrib/sse v1.1.0 // indirect + github.com/gin-contrib/timeout v1.1.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-openapi/jsonpointer v0.22.1 // indirect github.com/go-openapi/jsonreference v0.21.2 // indirect diff --git a/go.sum b/go.sum index 6424e83..efe2985 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ git.zhangdeman.cn/zhangdeman/consts v0.0.0-20260102134357-189dc7f57c1a h1:ppfx1Y git.zhangdeman.cn/zhangdeman/consts v0.0.0-20260102134357-189dc7f57c1a/go.mod h1:5p8CEKGBxi7qPtTXDI3HDmqKAfIm5i/aBWdrbkbdNjc= git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20251013092857-dcf591d4e8a8 h1:Pw981jG3hH9ZHrB3s1xPpsZafgX3USuMAjnGi2GEP9Y= git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20251013092857-dcf591d4e8a8/go.mod h1:xtCw3om5DRrG30EfQd/lfQPXgptfK7l9oBSt4Kdhjok= +git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20251207071238-9aa24be3d708 h1:yVr38JAgPwS/6JeYdHLDa8PXU3fTa2dnENL1JGdu3ns= +git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20251207071238-9aa24be3d708/go.mod h1:iwegDT/6mX2INyxMAYxsL9pZdpEixiu1GdpHIG2It1k= 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= @@ -16,8 +18,12 @@ git.zhangdeman.cn/zhangdeman/graceful v0.0.0-20250529070945-92833db6f3a4 h1:d1B3 git.zhangdeman.cn/zhangdeman/graceful v0.0.0-20250529070945-92833db6f3a4/go.mod h1:faaKb5d5tz3NmQQ+NrTnBDa1G/tN9/CVuKun1V4WBIE= git.zhangdeman.cn/zhangdeman/logger v0.0.0-20251031042950-416e962cbf3b h1:+ca511XlP+HoBa2zB/ERSIE6yTiqiXpsgqvs64kRAZA= git.zhangdeman.cn/zhangdeman/logger v0.0.0-20251031042950-416e962cbf3b/go.mod h1:tlQR2nfdP291Lug+b3BSu0q+kTPoSVNRL5dPq2nv9zQ= +git.zhangdeman.cn/zhangdeman/logger v0.0.0-20251231045117-f05cb1e30afe h1:/AeCVO9xqsERJbhsSA6Uw+F5Dc+shR6MQbG30i4OS7c= +git.zhangdeman.cn/zhangdeman/logger v0.0.0-20251231045117-f05cb1e30afe/go.mod h1:mzy5JiGVcx8KnT8hUaXjngboHQm1k/b5JymO01ujZSI= git.zhangdeman.cn/zhangdeman/network v0.0.0-20251013095944-5b89fff39bde h1:+3zIOditaUwzSpl2ybM1PYN4OYTIKiemMBt+pNv3Yko= git.zhangdeman.cn/zhangdeman/network v0.0.0-20251013095944-5b89fff39bde/go.mod h1:Ewh0UYOqXxEh0khgHj9bDz1rbnd7cCCsJrcOTFX/8wg= +git.zhangdeman.cn/zhangdeman/network v0.0.0-20251220063845-8403861d36e5 h1:Dx5xvkIx3GHF6gIPhrJnANFYNWG514/9+PHhdGowNfc= +git.zhangdeman.cn/zhangdeman/network v0.0.0-20251220063845-8403861d36e5/go.mod h1:HG6674mvHXXADavdVRHebkcBOz6Zq6kCGKnTN0ukAXE= git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20251013024601-da007da2fb42 h1:VjYrb4adud7FHeiYS9XA0B/tOaJjfRejzQAlwimrrDc= git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20251013024601-da007da2fb42/go.mod h1:VHb9qmhaPDAQDcS6vUiDCamYjZ4R5lD1XtVsh55KsMI= git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20251013044511-86c1a4a3a9dd h1:kTZOpR8iHx27sUufMWVYhDZx9Q4h80j7RWlaR8GIBiU= @@ -26,10 +32,14 @@ git.zhangdeman.cn/zhangdeman/trace v0.0.0-20251013092356-b7b9fb5f8a76 h1:Y1GME5d git.zhangdeman.cn/zhangdeman/trace v0.0.0-20251013092356-b7b9fb5f8a76/go.mod h1:avN/muzbNjUM2qamRZeY4fuLEmA9cmfslk1dkdtRQBE= 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/util v0.0.0-20260103142706-1f6145405ec4 h1:x/xEkukbXS8WNN0N2A79C/q1Gh+fm3XrAdr1d/nEcXI= +git.zhangdeman.cn/zhangdeman/util v0.0.0-20260103142706-1f6145405ec4/go.mod h1:OKI+RVVfRTUf/ox9uDMydtos2YDFr+/UuU4FFZKgPYY= git.zhangdeman.cn/zhangdeman/websocket v0.0.0-20251013144324-313024336a6f h1:InxNoLPHBLwCLblW0lsL2P1ZBYoUEzw9Yh+KNLt4Xmg= git.zhangdeman.cn/zhangdeman/websocket v0.0.0-20251013144324-313024336a6f/go.mod h1:Pbs7tusW6RNcqrNCVcLE2zrM8JfPaO7lBJQuRiAzzLs= git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20251014035305-c0ec06fa6dff h1:ym1Qs4diJe27CK/0K6vy7RvgH90mXgslWA++L8mXaKE= git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20251014035305-c0ec06fa6dff/go.mod h1:mBvTwcdqHRF3QIkAh92j/JRhru2LzyJ2LBqolxjzzKE= +git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20251225094759-09c64ba2541c h1:lTShwLIIBojEInQlQYmKvpoio5Srasn05bPyBIEXBsY= +git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20251225094759-09c64ba2541c/go.mod h1:oSmLgHs4EausBSmH4GdpGUtjubPek8hLXTAUc4cPCb0= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= @@ -45,6 +55,7 @@ github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gE github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= @@ -55,6 +66,8 @@ github.com/gin-contrib/pprof v1.5.3 h1:Bj5SxJ3kQDVez/s/+f9+meedJIqLS+xlkIVDe/lcv github.com/gin-contrib/pprof v1.5.3/go.mod h1:0+LQSZ4SLO0B6+2n6JBzaEygpTBxe/nI+YEYpfQQ6xY= 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-contrib/timeout v1.1.0 h1:WAmWseo5gfBUbMrMJu5hJxDclehfSJUmK2wGwCC/EFw= +github.com/gin-contrib/timeout v1.1.0/go.mod h1:NpRo4gd1Ad8ZQ4T6bQLVFDqiplCmPRs2nvfckxS2Fw4= github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= @@ -208,6 +221,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg= diff --git a/middleware/timeout.go b/middleware/timeout.go new file mode 100644 index 0000000..b95a982 --- /dev/null +++ b/middleware/timeout.go @@ -0,0 +1,34 @@ +// Package middleware ... +// +// Description : middleware ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2026-01-04 10:17 +package middleware + +import ( + "net/http" + "time" + + "github.com/gin-contrib/timeout" + "github.com/gin-gonic/gin" +) + +// Timeout 超时处理中间件 +func Timeout(ttl int64) func(ctx *gin.Context) { + if ttl <= 0 { + // 未设置超时 + return func(ctx *gin.Context) { + ctx.Next() + } + } + // 设置超时中间件, 单位: ms + return timeout.New( + timeout.WithTimeout(time.Duration(ttl)*time.Millisecond), + timeout.WithResponse(func(ctx *gin.Context) { + ctx.JSON(http.StatusRequestTimeout, gin.H{"code": http.StatusRequestTimeout, "msg": "请求超时"}) + ctx.Abort() + }), + ) +} diff --git a/router/controller.go b/router/controller.go index c2fac52..3c058a2 100644 --- a/router/controller.go +++ b/router/controller.go @@ -153,7 +153,7 @@ func (c controllerParser) setUriMeta(metaField reflect.StructField, cfg *UriConf cfg.NoLogin = boolMetaParse(TagNameNoLogin) // 是否需要登录 // 最大执行时间 - cfg.MaxExecTime = uint(0) + cfg.MaxExecTime = int64(0) if tagVal := strings.ToLower(metaField.Tag.Get(TagNameMaxExecTime)); tagVal != "" { if err := util.ConvertAssign(&cfg.MaxExecTime, tagVal); nil != err { panic(cfg.Path + " : 最大执行时间配置错误(配置的值必须是无符号整型), 请检查配置 : " + err.Error()) diff --git a/router/define.go b/router/define.go index d6c2cd7..5881a93 100644 --- a/router/define.go +++ b/router/define.go @@ -44,7 +44,7 @@ type UriConfig struct { IsSse bool `json:"is_sse"` // 是否 SSE 连接 IsWebsocket bool `json:"is_ws"` // 是否 websocket 连接 OutputStrict bool `json:"output_strict"` // 接口是否为严格模式 : 不配置,可返回任意类型, 配置, 必须返回结构体或者map - MaxExecTime uint `json:"max_exec_time"` // 接口最大执行时间, 单位: ms, 配置为0则不验证, 注意, 超时后不会报错, 会打印一条warn日志, 如果配置了报警策略, 也会发送报警信息 + MaxExecTime int64 `json:"max_exec_time"` // 接口最大执行时间, 单位: ms, 配置为0则不验证, 注意, 超时后不会报错, 会打印一条warn日志, 如果配置了报警策略, 也会发送报警信息 HookSync bool `json:"hook_sync"` // 接口主逻辑执行完成之后,hook是否同步执行, 默认异步执行 NoLogin bool `json:"no_login"` // 接口是否需要登录(无需登录, 则有token就验证, 无token不验证) ParamIsPtr bool `json:"param_is_ptr"` // 参数是否指针类型 diff --git a/router/server.go b/router/server.go index dfe22be..db4aae1 100644 --- a/router/server.go +++ b/router/server.go @@ -203,6 +203,8 @@ func (s *server) Group(routerPrefix string, middlewareList []gin.HandlerFunc, co } else { apiMiddlewareList = append(apiMiddlewareList, runtime.FuncForPC(reflect.ValueOf(s.RequestHandler).Pointer()).Name()) } + // 设置 超时 函数描述 + apiMiddlewareList = append(apiMiddlewareList, runtime.FuncForPC(reflect.ValueOf(middleware.Timeout).Pointer()).Name()) // 设置 logic 函数描述 apiMiddlewareList = append(apiMiddlewareList, runtime.FuncForPC(itemUriCfg.ApiLogicFunc.Func.Pointer()).Name()) @@ -231,21 +233,25 @@ func (s *server) Group(routerPrefix string, middlewareList []gin.HandlerFunc, co // registerRouter 注册路由 func (s *server) registerRouter(routerGroup *gin.RouterGroup, method string, itemUriCfg UriConfig, handleFunc gin.HandlerFunc) { + funcList := []gin.HandlerFunc{ + middleware.Timeout(itemUriCfg.MaxExecTime), // 超时处理 + handleFunc, + } switch method { case http.MethodGet: routerGroup.GET(itemUriCfg.Path, handleFunc) case http.MethodHead: - routerGroup.HEAD(itemUriCfg.Path, handleFunc) + routerGroup.HEAD(itemUriCfg.Path, funcList...) case http.MethodPost: - routerGroup.POST(itemUriCfg.Path, handleFunc) + routerGroup.POST(itemUriCfg.Path, funcList...) case http.MethodPut: - routerGroup.PUT(itemUriCfg.Path, handleFunc) + routerGroup.PUT(itemUriCfg.Path, funcList...) case http.MethodPatch: - routerGroup.PATCH(itemUriCfg.Path, handleFunc) + routerGroup.PATCH(itemUriCfg.Path, funcList...) case http.MethodDelete: - routerGroup.DELETE(itemUriCfg.Path, handleFunc) + routerGroup.DELETE(itemUriCfg.Path, funcList...) case http.MethodOptions: - routerGroup.OPTIONS(itemUriCfg.Path, handleFunc) + routerGroup.OPTIONS(itemUriCfg.Path, funcList...) case http.MethodTrace: panic(`method Trace is not supported`) default: