Compare commits

...
9 Commits
Author SHA1 Message Date
19904408334 e47dd99816 feat: 支持流式和非解析HTTP请求及单条DB查询
重构HTTP请求模块,提取doRequestRaw基础方法,新增流式请求(PostStream)、非解析请求(GetNotParse/PostNotParse)及原始响应读取能力;同时在Gfdb接口中新增GetOne单条记录查询方法。
2026-07-23 17:09:27 +08:00
admin 272943d238 运维脚本调整 2026-07-02 11:56:28 +08:00
admin 172c1cc506 common版本更新 2026-06-25 14:55:50 +08:00
admin 915e1f65ec common版本回退 2026-06-24 10:47:47 +08:00
admin c512327358 common版本升级 2026-06-24 09:50:05 +08:00
admin c091ed4984 jaeger修改 2026-06-24 09:41:34 +08:00
admin dc4dd5dc62 common版本升级 2026-06-23 18:17:41 +08:00
admin 7e51069595 jaeger修改 2026-06-23 16:51:39 +08:00
19904408334 791c9905df fix: 修正回调地址生成方式 2026-06-22 11:26:49 +08:00
5 changed files with 69 additions and 19 deletions
+1
View File
@@ -0,0 +1 @@
.git
+1
View File
@@ -439,6 +439,7 @@ var (
type Gfdb interface {
GetAll(ctx context.Context, sql string, args ...any) (gdb.Result, error)
GetOne(ctx context.Context, sql string, args ...any) (gdb.Record, error)
Exec(ctx context.Context, sql string, args ...any) (sql.Result, error)
Model(ctx context.Context, tableNameOrStruct ...any) *model
Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) error
+1
View File
@@ -1,4 +1,5 @@
module gitea.redpowerfuture.com/red-future/common
go 1.26.0
require (
+64 -18
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"io"
"net/http"
"reflect"
"regexp"
@@ -69,10 +70,10 @@ func SkipMiddleware(h func(r *ghttp.Request), path string) (handler ghttp.Handle
}
func RouteRegister(controllers []interface{}) {
//Httpserver.Group("/log", func(group *ghttp.RouterGroup) {
// group.Middleware(jaeger.NewTracer)
// group.Bind(controller.OperationLog)
//})
Httpserver.Group("/log", func(group *ghttp.RouterGroup) {
group.Middleware(jaeger.NewTracer)
//group.Bind(controller.OperationLog)
})
re := regexp.MustCompile("[A-Z]")
for _, t := range controllers {
sName := reflect.ValueOf(t).Elem().Type().Name()
@@ -80,19 +81,15 @@ func RouteRegister(controllers []interface{}) {
return fmt.Sprintf("/%s", strings.ToLower(s))
})
Httpserver.Group(convertedStr, func(group *ghttp.RouterGroup) {
group.Middleware(jaeger.NewTracer)
group.Bind(t)
})
}
go Httpserver.Run()
}
// doRequest 统一HTTP请求处理(DELETE用ContentJson发送bodygconv.Struct增加err检查)
func doRequest(ctx context.Context, method string, url string, headers map[string]string, target any, data ...any) (err error) {
err = utils.ValidStructPtr(target)
if err != nil {
return
}
// doRequestRaw 执行HTTP请求,返回gclient.Response,调用方需自行Close
// 统一处理:client克隆、ContentJson设置、请求头注入、GET查询参数转换
func doRequestRaw(ctx context.Context, method string, url string, headers map[string]string, data ...any) (*gclient.Response, error) {
client := Httpclient.Clone()
// POST/PUT/DELETE请求都需要显式用ContentJson序列化body
@@ -110,9 +107,9 @@ func doRequest(ctx context.Context, method string, url string, headers map[strin
// 修复:避免data...展开导致的双重包装问题
// 当只有一个元素时,直接传递该元素,避免被包装成数组
var response *gclient.Response
var err error
// 对于GET请求,将参数转换为map
if method == http.MethodGet && len(data) > 0 && len(data)%2 == 0 {
// 构建query参数map
queryParams := make(map[string]string)
for i := 0; i < len(data); i += 2 {
if key, ok := data[i].(string); ok && i+1 < len(data) {
@@ -126,17 +123,33 @@ func doRequest(ctx context.Context, method string, url string, headers map[strin
} else {
response, err = client.DoRequest(ctx, method, url, data...)
}
return response, err
}
// doRequest 统一HTTP请求处理(同步/异步,解析内部API响应格式并填充target)
func doRequest(ctx context.Context, method string, url string, headers map[string]string, target any, respParse bool, data ...any) (res []byte, err error) {
if target != nil || respParse {
err = utils.ValidStructPtr(target)
if err != nil {
return
}
}
response, err := doRequestRaw(ctx, method, url, headers, data...)
if err != nil {
return
}
defer response.Close()
result := response.ReadAll()
if !respParse {
return result, nil
}
// 统一处理内部API响应格式:{code:200,message:"",data:{...}}
resultStrut := &ghttp.DefaultHandlerResponse{}
if err = gconv.Struct(result, &resultStrut); err != nil { // 修复:增加err检查
return errors.New("响应解析失败: " + err.Error())
return nil, errors.New("响应解析失败: " + err.Error())
}
// 添加调试日志:打印解析后的结构
@@ -145,7 +158,7 @@ func doRequest(ctx context.Context, method string, url string, headers map[strin
if resultStrut.Code == 200 || resultStrut.Code == 0 {
if err = gconv.Struct(resultStrut.Data, target); err != nil { // 修复:增加err检查
return errors.New("数据解析失败: " + err.Error())
return nil, errors.New("数据解析失败: " + err.Error())
}
// 添加调试日志:打印最终的target
g.Log().Debugf(ctx, "[HTTP] 最终target: %+v", target)
@@ -154,19 +167,52 @@ func doRequest(ctx context.Context, method string, url string, headers map[strin
}
return
}
func Get(ctx context.Context, url string, headers map[string]string, target any, data ...any) (err error) {
err = doRequest(ctx, http.MethodGet, url, headers, target, data...)
_, err = doRequest(ctx, http.MethodGet, url, headers, target, true, data...)
return
}
func Post(ctx context.Context, url string, headers map[string]string, target any, data ...any) (err error) {
err = doRequest(ctx, http.MethodPost, url, headers, target, data...)
_, err = doRequest(ctx, http.MethodPost, url, headers, target, true, data...)
return
}
func Put(ctx context.Context, url string, headers map[string]string, target any, data ...any) (err error) {
err = doRequest(ctx, http.MethodPut, url, headers, target, data...)
_, err = doRequest(ctx, http.MethodPut, url, headers, target, true, data...)
return
}
func Delete(ctx context.Context, url string, headers map[string]string, target any, data ...any) (err error) {
err = doRequest(ctx, http.MethodDelete, url, headers, target, data...)
_, err = doRequest(ctx, http.MethodDelete, url, headers, target, true, data...)
return
}
func GetNotParse(ctx context.Context, url string, headers map[string]string, data ...any) (res []byte, err error) {
res, err = doRequest(ctx, http.MethodGet, url, headers, nil, false, data...)
return
}
func PostNotParse(ctx context.Context, url string, headers map[string]string, data ...any) (res []byte, err error) {
res, err = doRequest(ctx, http.MethodPost, url, headers, nil, false, data...)
return
}
// DoStream 流式HTTP请求,返回响应体io.ReadCloser,由调用方自行控制读取和关闭
// 注意:返回的是原始响应流,不会解析内部API响应格式,调用方必须在使用后Close
func doStream(ctx context.Context, method string, url string, headers map[string]string, data ...any) (io.ReadCloser, error) {
response, err := doRequestRaw(ctx, method, url, headers, data...)
if err != nil {
return nil, err
}
// 检查HTTP状态码,提前返回错误
if response.StatusCode < 200 || response.StatusCode >= 300 {
bodyBytes, _ := io.ReadAll(response.Body)
response.Close()
return nil, fmt.Errorf("[HTTP][Stream] 状态码异常: %d, body=%s", response.StatusCode, string(bodyBytes))
}
return response.Body, nil
}
// PostStream POST流式请求,返回响应体io.ReadCloser
func PostStream(ctx context.Context, url string, headers map[string]string, data ...any) (io.ReadCloser, error) {
return doStream(ctx, http.MethodPost, url, headers, data...)
}
+2 -1
View File
@@ -583,7 +583,8 @@ func GetLocalBaseURL(ctx context.Context) string {
// GetCallbackURL 获取回调地址(完整 URL)
func GetCallbackURL(ctx context.Context, path string) string {
baseURL := GetLocalBaseURL(ctx)
//baseURL := GetLocalBaseURL(ctx)
baseURL := "http://" + GetLocalAddress(ctx)
// 确保 path 以 / 开头
if !strings.HasPrefix(path, "/") {
path = "/" + path