From 94aaccaa9cfce829464cd4e9dc9e1e5e0b94fb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 26 Dec 2025 17:48:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=86=E5=A4=87=E6=94=AF=E6=8C=81=20sse=20?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 2 ++ router/handler.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6c89395..c9c34ea 100644 --- a/go.mod +++ b/go.mod @@ -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-20251226040044-6bc8da22219a + git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251226093912-de8914503463 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 diff --git a/go.sum b/go.sum index bcec335..015c2ab 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251217031322-9e8b61fd5156 h1:VaaejW git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251217031322-9e8b61fd5156/go.mod h1:5p8CEKGBxi7qPtTXDI3HDmqKAfIm5i/aBWdrbkbdNjc= git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251226040044-6bc8da22219a h1:p85je5ExTyUsd2jR+Lq2rSJneAPM3MkuUhFHH+TfhEM= git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251226040044-6bc8da22219a/go.mod h1:5p8CEKGBxi7qPtTXDI3HDmqKAfIm5i/aBWdrbkbdNjc= +git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251226093912-de8914503463 h1:IEUkYzFIWoxQwoJ1c16mDrBuYUgQzYCQ7YHkWXsb5uo= +git.zhangdeman.cn/zhangdeman/consts v0.0.0-20251226093912-de8914503463/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= diff --git a/router/handler.go b/router/handler.go index 58bacf8..d8e21ca 100644 --- a/router/handler.go +++ b/router/handler.go @@ -123,3 +123,84 @@ func (s *server) RequestHandler(uriCfg UriConfig) gin.HandlerFunc { }) } } + +// SseHandler sse连接请求 +func (s *server) SseHandler(uriCfg UriConfig) gin.HandlerFunc { + return func(ctx *gin.Context) { + var ( + err error + ok bool + e exception.IException + formValue any + firstParam reflect.Value + ) + + if formValue, err = s.getFormInitValue(ctx, uriCfg); nil != err { + e = exception.NewFromError(http.StatusBadRequest, err) + response.SendWithException(ctx, e, &define.ResponseOption{ + ContentType: consts.MimeTypeJson, + }) + ctx.Abort() + return + } + // 表单数据 + inputValue := reflect.ValueOf(formValue).Elem() + + // 注入公共参数 + if err = s.injectCommonParam(ctx, inputValue); nil != err { + e = exception.NewFromError(500, err) + response.SendWithException(ctx, e, &define.ResponseOption{ + ContentType: consts.MimeTypeJson, + }) + ctx.Abort() + return + } + + // 非必传参数设置默认值 + defaults.SetDefaults(formValue) + + // 默认请求失败 + ctx.Set(consts.GinRequestSuccess, false) + // 初始化响应之后 logic + logicAfterResponse := &define.LogicAfterResponse{ + SuccessHookFuncList: make([]func(ctx *gin.Context), 0), + FailureHookFuncList: make([]func(ctx *gin.Context), 0), + Lock: &sync.RWMutex{}, + } + // 此处暴露出去,是为了使用方可以获取到对应数据 + ctx.Set(consts.GinLogicAfterResponseKey, logicAfterResponse) + defer s.hook(ctx, uriCfg) // 执行 Logic 之后的相关逻辑 + + ctx.Writer.Header().Set(consts.HeaderKeyContentType.String(), "text/event-stream") + ctx.Writer.Header().Set(consts.HeaderKeyCacheControl.String(), "no-cache") + ctx.Writer.Header().Set(consts.HeaderKeyConnection.String(), "keep-alive") + ctx.Writer.Header().Set(consts.HeaderKeyXAccelBuffering.String(), "no") + flusher, _ := ctx.Writer.(http.Flusher) + // TODO: 发送连接就绪消息 + flusher.Flush() + firstParam = reflect.ValueOf(ctx) + resList := uriCfg.ApiLogicFunc.Func.Call([]reflect.Value{uriCfg.ApiStructValue, firstParam, inputValue}) + if resList[1].IsNil() { + // 请求成功, 更新标识 + ctx.Set(consts.GinRequestSuccess, true) + response.SuccessWithExtension(ctx, resList[0].Interface(), &define.ResponseOption{ContentType: consts.MimeTypeJson}) + return + } + // 请求失败 + if ok = errors.As(resList[1].Interface().(error), &e); ok { + // 本身就是exception.IException + logger.Instance.Debug("请求结果err类型为 exception.IException, 无需特殊处理", loggerPkg.NewLogData(util.GinCtxToContext(ctx), logger.RecordType, logger.CodeLogicErrorWrapper, map[string]any{}).ToFieldList()...) + } else if err, ok = resList[1].Interface().(error); ok { + logger.Instance.Debug("请求结果err类型为 error, 包装为 exception.IException", loggerPkg.NewLogData(util.GinCtxToContext(ctx), logger.RecordType, logger.CodeLogicErrorWrapper, map[string]any{}).ToFieldList()...) + e = exception.NewFromError(-1, err) + } else { + logger.Instance.Debug("请求结果err类型 既不是 error 也不是 exception.IException, 包装为 exception.IException", loggerPkg.NewLogData(util.GinCtxToContext(ctx), logger.RecordType, logger.CodeLogicErrorWrapper, map[string]any{}).ToFieldList()...) + e = exception.NewWithCodeAndData(-1, map[string]any{ + "err": resList[1].Interface(), + }) + } + response.SendWithException(ctx, e, &define.ResponseOption{ + ContentType: consts.MimeTypeJson, + }) + } +}