feat: 升级hook处理逻辑

This commit is contained in:
2025-11-01 17:16:11 +08:00
parent 954f6fef8a
commit d4052bcc4f
8 changed files with 95 additions and 42 deletions

View File

@ -12,6 +12,7 @@ import (
"git.zhangdeman.cn/zhangdeman/consts"
"git.zhangdeman.cn/zhangdeman/wrapper/op_ternary"
"github.com/gin-gonic/gin"
)
var (
@ -127,22 +128,18 @@ func GetHttpHandleConfig() *HttpHandleConfig {
}
}
const (
LogicAfterResponseKey = "__logic_after_response__"
)
type LogicAfterResponse struct {
SuccessHookFuncList []func() `json:"-"` // 请求最后需要执行的成功hook函数
FailureHookFuncList []func() `json:"-"` // 请求最后需要执行的失败hook函数
SuccessHookFuncList []func(ctx *gin.Context) `json:"-"` // 请求最后需要执行的成功hook函数
FailureHookFuncList []func(ctx *gin.Context) `json:"-"` // 请求最后需要执行的失败hook函数
Lock *sync.RWMutex `json:"-"` // 逻辑锁
}
func (logic *LogicAfterResponse) AddSuccessHook(f func()) {
func (logic *LogicAfterResponse) AddSuccessHook(f func(ctx *gin.Context)) {
logic.Lock.Lock()
defer logic.Lock.Unlock()
logic.SuccessHookFuncList = append(logic.SuccessHookFuncList, f)
}
func (logic *LogicAfterResponse) AddFailureHook(f func()) {
func (logic *LogicAfterResponse) AddFailureHook(f func(ctx *gin.Context)) {
logic.Lock.Lock()
defer logic.Lock.Unlock()
logic.FailureHookFuncList = append(logic.FailureHookFuncList, f)

2
go.mod
View File

@ -6,7 +6,7 @@ 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-20250916024308-d378e6c57772
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251101052451-27b111113aa3
git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20251013092857-dcf591d4e8a8
git.zhangdeman.cn/zhangdeman/exception v0.0.0-20250510123912-a0d52fc093ab
git.zhangdeman.cn/zhangdeman/graceful v0.0.0-20250529070945-92833db6f3a4

2
go.sum
View File

@ -2,6 +2,8 @@ git.zhangdeman.cn/zhangdeman/api-doc v1.0.3-0.20251013152001-868ee8955623 h1:Qiq
git.zhangdeman.cn/zhangdeman/api-doc v1.0.3-0.20251013152001-868ee8955623/go.mod h1:ryyMI2gPgotFD1lZC50p2vRyX8bf3MRwO9tos41z4WU=
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250916024308-d378e6c57772 h1:Yo1ur3LnDF5s7F7tpJsNrdUSF8LwYKnN9TdQU32F3eU=
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250916024308-d378e6c57772/go.mod h1:5p8CEKGBxi7qPtTXDI3HDmqKAfIm5i/aBWdrbkbdNjc=
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251101052451-27b111113aa3 h1:MQJCu5ZIDUYJSQ7rGZni4gsxgGmpXgWgNBHJzHSOvxw=
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251101052451-27b111113aa3/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/easylock v0.0.0-20230731062340-983985c12eda h1:bMD6r9gjRy7cO+T4zRQVYAesgIblBdTnhzT1vN5wjvI=

View File

@ -10,7 +10,7 @@ package logger
import "go.uber.org/zap"
var (
Instance *zap.Logger = zap.NewNop()
Instance = zap.NewNop()
)
// SetInstance 设置日志实例
@ -27,4 +27,5 @@ const (
const (
CodeInjectCommonParam = "inject-common-param"
CodeLogicHook = "logic-hook"
)

View File

@ -109,6 +109,8 @@ func (c controller) methodConfig(reflectMethod reflect.Method) (cfg UriConfig, n
cfg.TagList = strings.Split(metaField.Tag.Get(TagNameUriTag), ",")
// 解析第一个返回值, 要求必须是结构体或者是map
outputStrictModel := metaField.Tag.Get(TagNameOutputStrict)
hookSync := strings.ToLower(metaField.Tag.Get(TagNameHookSync))
cfg.HookSync = hookSync == "1" || hookSync == "true" // 同步执行判断
cfg.OutputStrict = outputStrictModel == "1" || outputStrictModel == "true"
if cfg.OutputStrict {
// 开启输出严格模式校验

View File

@ -25,6 +25,7 @@ const (
TagNameUriTag = "tag" // 接口的tag
TagNameDesc = "desc" // 接口的描述
TagNameOutputStrict = "output_strict" // 接口数据是否为严格模式 : 严格模式, 响应数据必须是结构体/map非严格模式返回任意值
TagNameHookSync = "hook-sync" // hook同步执行
TagNameBinding = "binding" // gin 内置的验证规则tag
TagNameValidate = "validate" // validator v10 默认的验证规则tag
TagNameErrMsg = "err" // 验证失败错误信息tag
@ -41,6 +42,7 @@ type UriConfig struct {
TagList []string `json:"tag_list"` // 接口分组
Desc string `json:"desc"` // 接口描述
OutputStrict bool `json:"output_strict"` // 接口是否为严格模式 : 不配置,可返回任意类型, 配置, 必须返回结构体或者map
HookSync bool `json:"hook_sync"` // 接口主逻辑执行完成之后hook是否同步执行, 默认异步执行
FormDataType reflect.Type `json:"-"` // 表单数据类型
ResultDataType reflect.Type `json:"-"` // 返回值数据类型
ApiStructValue reflect.Value `json:"-"` // 逻辑函数所属结构体取值
@ -48,10 +50,6 @@ type UriConfig struct {
}
// UriParam 接口参数配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:40 2025/1/27
type UriParam struct {
Field string `json:"field"` // 结构体字段
Name string `json:"name"` // 参数名称

View File

@ -78,7 +78,8 @@ func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
// 非必传参数设置默认值
defaults.SetDefaults(formValue)
isSuccess := false
// 默认请求失败
ctx.Set(consts.GinRequestSuccess, false)
// 初始化响应之后logic
logicAfterResponse := &define.LogicAfterResponse{
SuccessHookFuncList: make([]func(), 0),
@ -86,30 +87,8 @@ func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
Lock: &sync.RWMutex{},
}
// 此处暴露出去,是为了使用方可以获取到对应数据
ctx.Set(define.LogicAfterResponseKey, logicAfterResponse)
defer func() {
go func() {
// 执行响应之后的相关逻辑
defer func() {
if r := recover(); r != nil {
}
}()
if isSuccess {
for _, itemFunc := range logicAfterResponse.SuccessHookFuncList {
if nil != itemFunc {
itemFunc()
}
}
} else {
for _, itemFunc := range logicAfterResponse.FailureHookFuncList {
if nil != itemFunc {
itemFunc()
}
}
}
}()
}()
ctx.Set(consts.GinLogicAfterResponseKey, logicAfterResponse)
defer s.hook(ctx, uriCfg) // 执行Logic之后的相关逻辑
// 执行逻辑
if uriCfg.FormDataType.Kind() != reflect.Ptr {
inputValue = inputValue.Elem()
@ -118,8 +97,8 @@ func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc {
firstParam = reflect.ValueOf(ctx)
resList := uriCfg.ApiLogicFunc.Func.Call([]reflect.Value{uriCfg.ApiStructValue, firstParam, inputValue})
if resList[1].IsNil() {
// 请求成功
isSuccess = true
// 请求成功, 更新标识
ctx.Set(consts.GinRequestSuccess, true)
response.SuccessWithExtension(ctx, resList[0].Interface(), &define.ResponseOption{ContentType: consts.MimeTypeJson})
return
}

74
router/hook.go Normal file
View File

@ -0,0 +1,74 @@
// Package router ...
//
// Description : router ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2025-11-01 12:34
package router
import (
"git.zhangdeman.cn/zhangdeman/consts"
"git.zhangdeman.cn/zhangdeman/gin/define"
"git.zhangdeman.cn/zhangdeman/gin/logger"
"git.zhangdeman.cn/zhangdeman/gin/util"
pkgLogger "git.zhangdeman.cn/zhangdeman/logger"
"github.com/gin-gonic/gin"
)
// hook 执行hook逻辑
func (s *server) hook(ctx *gin.Context, uriCfg UriConfig) {
responseAfter, exist := ctx.Get(consts.GinLogicAfterResponseKey)
innerContext := util.GinCtxToContext(ctx)
if !exist || nil != responseAfter {
// 未配置
logger.Instance.Debug("未配置Logic执行后的hook逻辑", pkgLogger.NewLogData(innerContext, logger.RecordType, logger.CodeLogicHook, map[string]any{
"uri": uriCfg.Path,
"logic_after_response_key": consts.GinLogicAfterResponseKey,
}).ToFieldList()...)
return
}
isSuccess, exist := ctx.Get(consts.GinRequestSuccess)
success := false
if nil != isSuccess && (isSuccess == "1" || isSuccess == "true" || isSuccess.(bool)) {
success = true
}
hookInstance := responseAfter.(*define.LogicAfterResponse)
if uriCfg.HookSync {
// 同步执行
s.hookAfter(ctx, uriCfg, hookInstance, success)
} else {
// 异步执行
go s.hookAfter(ctx, uriCfg, hookInstance, success)
}
}
func (s *server) hookAfter(ctx *gin.Context, uriCfg UriConfig, hookInstance *define.LogicAfterResponse, success bool) {
innerContext := util.GinCtxToContext(ctx)
defer func() {
if err := recover(); err != nil {
logger.Instance.Error("hook执行异常", pkgLogger.NewLogData(innerContext, logger.RecordType, logger.CodeLogicHook, map[string]any{
"uri": uriCfg.Path,
"logic_after_response_key": consts.GinLogicAfterResponseKey,
"error": err.(error).Error(),
"logic_success": success,
}).ToFieldList()...)
} else {
}
}()
if success {
logger.Instance.Debug("接口Logic执行成功, 执行Hook逻辑")
for _, itemFunc := range hookInstance.SuccessHookFuncList {
if nil != itemFunc {
itemFunc(ctx)
}
}
} else {
for _, itemFunc := range hookInstance.FailureHookFuncList {
if nil != itemFunc {
itemFunc(ctx)
}
}
}
}