package httpx import ( "context" "encoding/json" "fmt" "net/url" "sync" "time" "github.com/cloudwego/hertz/pkg/app/client" "github.com/cloudwego/hertz/pkg/protocol" "github.com/cloudwego/hertz/pkg/protocol/consts" ) var ( once sync.Once clientInstance *HertzClient ) // HertzClient 定义 type HertzClient struct { Client *client.Client Timeout time.Duration Header map[string]string } // Init 初始化单例 func Init() { once.Do(func() { c, _ := client.NewClient() clientInstance = &HertzClient{ Client: c, Timeout: 5 * time.Second, Header: make(map[string]string), } }) } // SetHeader 设置默认 header func SetHeader(key, value string) { if clientInstance == nil { Init() } clientInstance.Header[key] = value } // 支持 value 为任意类型 func buildQueryString(query map[string][]any) string { if len(query) == 0 { return "" } values := url.Values{} for k, arr := range query { for _, v := range arr { values.Add(k, fmt.Sprintf("%v", v)) // 自动转 string } } return values.Encode() } func Get(ctx context.Context, urlStr string, query map[string][]any) (int, string, error) { if clientInstance == nil { Init() } h := clientInstance req := &protocol.Request{} res := &protocol.Response{} req.Header.SetMethod(consts.MethodGet) req.SetRequestURI(urlStr) if qs := buildQueryString(query); qs != "" { req.SetQueryString(qs) } for k, v := range h.Header { req.Header.Set(k, v) } ctx, cancel := context.WithTimeout(ctx, h.Timeout) defer cancel() err := h.Client.Do(ctx, req, res) if err != nil { return 0, "", err } return res.StatusCode(), string(res.Body()), nil } func PostJSON(ctx context.Context, urlStr string, query map[string][]any, payload any) (int, string, error) { if clientInstance == nil { Init() } h := clientInstance req := &protocol.Request{} res := &protocol.Response{} req.Header.SetMethod(consts.MethodPost) req.Header.SetContentTypeBytes([]byte("application/json")) req.SetRequestURI(urlStr) if qs := buildQueryString(query); qs != "" { req.SetQueryString(qs) } data, err := json.Marshal(payload) if err != nil { return 0, "", fmt.Errorf("marshal json error: %w", err) } req.SetBody(data) for k, v := range h.Header { req.Header.Set(k, v) } ctx, cancel := context.WithTimeout(ctx, h.Timeout) defer cancel() err = h.Client.Do(ctx, req, res) if err != nil { return 0, "", err } return res.StatusCode(), string(res.Body()), nil } func PostForm(ctx context.Context, urlStr string, query map[string][]any, form map[string]string) (int, string, error) { if clientInstance == nil { Init() } h := clientInstance req := &protocol.Request{} res := &protocol.Response{} req.Header.SetMethod(consts.MethodPost) req.SetRequestURI(urlStr) if qs := buildQueryString(query); qs != "" { req.SetQueryString(qs) } req.SetFormData(form) for k, v := range h.Header { req.Header.Set(k, v) } ctx, cancel := context.WithTimeout(ctx, h.Timeout) defer cancel() err := h.Client.Do(ctx, req, res) if err != nil { return 0, "", err } return res.StatusCode(), string(res.Body()), nil } func JSONStringToMap(jsonStr string) (map[string]interface{}, error) { var result map[string]interface{} if err := json.Unmarshal([]byte(jsonStr), &result); err != nil { return nil, err } return result, nil }