Files
common/http/http.go
2026-03-12 08:51:28 +08:00

143 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package http
import (
"context"
"errors"
"fmt"
"net/http"
"reflect"
"regexp"
"strings"
_ "gitee.com/red-future---jilin-g/common/consul"
"gitee.com/red-future---jilin-g/common/jaeger"
"gitee.com/red-future---jilin-g/common/log/controller"
"gitee.com/red-future---jilin-g/common/utils"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gclient"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/net/gsvc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
)
var Httpserver = g.Server()
var Httpclient = g.Client()
func init() {
err := gtime.SetTimeZone("Asia/Shanghai")
if err != nil {
panic("设置时区失败")
}
//s.Use(common.Cors) //中间件验证
//s.EnablePProf() //启用性能分析
Httpserver.SetOpenApiPath("/api.json")
Httpserver.SetDumpRouterMap(true) //关闭打印路由注册信息
Httpserver.BindMiddlewareDefault(ghttp.MiddlewareHandlerResponse)
Httpclient.SetDiscovery(gsvc.GetRegistry())
}
func RouteRegister(controllers []interface{}) {
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()
convertedStr := re.ReplaceAllStringFunc(sName, func(s string) string {
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
}
client := Httpclient.Clone()
// POST/PUT/DELETE请求都需要显式用ContentJson序列化body
if (method == http.MethodPost || method == http.MethodPut || method == http.MethodDelete) && len(data) > 0 {
client = client.ContentJson()
}
// 最后设置headers确保不会被ContentJson覆盖
if len(headers) > 0 {
client.SetHeaderMap(headers)
} else {
client.SetHeader("Authorization", g.RequestFromCtx(ctx).GetHeader("Authorization"))
}
// 修复避免data...展开导致的双重包装问题
// 当只有一个元素时,直接传递该元素,避免被包装成数组
var response *gclient.Response
if len(data) == 1 {
response, err = client.DoRequest(ctx, method, url, data[0])
} else {
response, err = client.DoRequest(ctx, method, url, data...)
}
if err != nil {
return
}
defer response.Close()
result := response.ReadAll()
// 第三方API特例RAGFlow等第三方API响应格式为{code,data,message}一层结构直接解析原始JSON到target
// 内部API格式为{code:200,message:"",data:{...}}两层结构需经过DefaultHandlerResponse二次解析
// 判断依据URL包含/api/v1/不影响内部API调用
isThirdPartyAPI := strings.Contains(url, "/api/v1/")
if isThirdPartyAPI {
// 第三方API特例直接解析原始JSON到target不经过DefaultHandlerResponse
if err = gconv.Struct(result, target); err != nil {
return errors.New("第三方API响应解析失败: " + err.Error())
}
return
}
// 内部API保持原有逻辑先解析为DefaultHandlerResponse再提取data字段
resultStrut := &ghttp.DefaultHandlerResponse{}
if err = gconv.Struct(result, &resultStrut); err != nil { // 修复增加err检查
return errors.New("响应解析失败: " + err.Error())
}
// 添加调试日志:打印解析后的结构
g.Log().Debugf(ctx, "[HTTP] 解析后结构: Code=%d, Message=%s, Data类型=%T, Data值=%+v",
resultStrut.Code, resultStrut.Message, resultStrut.Data, resultStrut.Data)
if resultStrut.Code == 200 || resultStrut.Code == 0 {
if err = gconv.Struct(resultStrut.Data, target); err != nil { // 修复增加err检查
return errors.New("数据解析失败: " + err.Error())
}
// 添加调试日志打印最终的target
g.Log().Debugf(ctx, "[HTTP] 最终target: %+v", target)
} else {
err = errors.New(resultStrut.Message)
}
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...)
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...)
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...)
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...)
return
}