package http import ( "context" "fmt" "net/http" "reflect" "regexp" "strings" _ "gitea.com/red-future/common/consul" "gitea.com/red-future/common/jaeger" "gitea.com/red-future/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() Httpclient = g.Client() filterPaths = map[string]bool{"/": true, "/*": true, "/api.json": true} legalRegisteredPaths = make(map[string]bool) ) func init() { err := gtime.SetTimeZone("Asia/Shanghai") if err != nil { panic("设置时区失败") } //s.Use(common.Cors) //中间件验证 //s.EnablePProf() //启用性能分析 //Httpserver.BindMiddlewareDefault(validateFilterPathMiddleware) Httpserver.SetOpenApiPath("/api.json") Httpserver.SetDumpRouterMap(true) //关闭打印路由注册信息 Httpserver.BindMiddlewareDefault(ghttp.MiddlewareHandlerResponse) Httpclient.SetDiscovery(gsvc.GetRegistry()) } func validateFilterPathMiddleware(r *ghttp.Request) { path := r.URL.Path if filterPaths[path] && !legalRegisteredPaths[path] { routes := Httpserver.GetRoutes() for _, route := range routes { if filterPaths[route.Handler.Router.Uri] && route.Handler.Router.Uri != "/api.json" { g.Log().Errorf(r.GetCtx(), "路径 %s 中间件 %s 必须通过 SkipMiddleware 注册", route.Handler.Router.Uri, route.Handler.Name) } } r.ExitAll() } r.Middleware.Next() } func SkipMiddleware(h func(r *ghttp.Request), path string) (handler ghttp.HandlerFunc) { if filterPaths[path] { legalRegisteredPaths[path] = true } return func(r *ghttp.Request) { if filterPaths[path] { r.Middleware.Next() return } h(r) } } 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发送body,gconv.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 // 对于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) { queryParams[key] = gconv.String(data[i+1]) } } g.Log().Infof(ctx, "[HTTP] GET请求构建的query参数: %+v", queryParams) response, err = client.DoRequest(ctx, method, url, queryParams) } else 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响应格式:{code:200,message:"",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 }