package http import ( "encoding/base64" "fmt" "net/http" "sync" "time" "git.x2erp.com/qdy/go-base/config" "github.com/go-resty/resty/v2" ) // HTTPClient 简化的HTTP客户端 type HTTPClient struct { client *resty.Client } // HTTPFactory HTTP客户端工厂 type HTTPFactory struct { config config.IConfig client *resty.Client } var ( httpFactoryInstance *HTTPFactory httpFactoryOnce sync.Once httpFactoryInitErr error ) // GetHTTPFactory 获取HTTP工厂单例实例 func GetHTTPFactory() (*HTTPFactory, error) { httpFactoryOnce.Do(func() { cfg := config.GetConfig() if err := config.GetInitError(); err != nil { httpFactoryInitErr = fmt.Errorf("failed to load config: %v", err) return } httpConfig := cfg.GetHTTP() // 创建共享的resty客户端(线程安全) client := resty.New() client.SetTimeout(time.Duration(httpConfig.Timeout) * time.Second) client.SetTransport(&http.Transport{ MaxIdleConns: httpConfig.MaxIdleConns, MaxIdleConnsPerHost: httpConfig.MaxIdleConnsPerHost, IdleConnTimeout: time.Duration(httpConfig.IdleConnTimeout) * time.Second, MaxConnsPerHost: httpConfig.MaxConnsPerHost, DisableCompression: httpConfig.DisableCompression, DisableKeepAlives: httpConfig.DisableKeepAlives, }) // 设置默认headers client.SetHeaders(map[string]string{ "Content-Type": "application/json", "Accept": "application/json", }) httpFactoryInstance = &HTTPFactory{ config: cfg, client: client, } }) return httpFactoryInstance, httpFactoryInitErr } // CreateClient 创建HTTP客户端包装器(共享底层resty.Client) func (f *HTTPFactory) CreateClient() *HTTPClient { return &HTTPClient{ client: f.client, // 共享同一个线程安全的客户端 } } // GetUnderlyingClient 获取底层resty客户端(用于特殊场景) func (f *HTTPFactory) GetUnderlyingClient() *resty.Client { if f == nil { return nil } return f.client } // CreateClient 全局便捷函数:创建HTTP客户端 func CreateClient() (*HTTPClient, error) { factory, err := GetHTTPFactory() if err != nil { return nil, err } return factory.CreateClient(), nil } // GetInitError 获取初始化错误(如果有) func GetInitError() error { return httpFactoryInitErr } // ==================== HTTPClient 方法 ==================== // SetAuthToken 设置认证token(请求级别) func (c *HTTPClient) SetAuthToken(token string) *HTTPClient { // 注意:这里设置的是客户端级别的token,会影响所有使用该客户端的请求 // 对于多用户场景,应该在请求级别设置 c.client.SetAuthToken(token) return c } // SetBearerToken 设置Bearer Token认证头(请求级别) func (c *HTTPClient) SetBearerToken(token string) *HTTPClient { if token != "" { c.client.SetHeader("Authorization", "Bearer "+token) } else { c.client.Header.Del("Authorization") } return c } // SetBasicAuth 设置Basic认证头(请求级别) func (c *HTTPClient) SetBasicAuth(username, password string) *HTTPClient { if username != "" && password != "" { auth := username + ":" + password token := base64.StdEncoding.EncodeToString([]byte(auth)) c.client.SetHeader("Authorization", "Basic "+token) } else { c.client.Header.Del("Authorization") } return c } // SetJSONContentType 设置Content-Type为application/json func (c *HTTPClient) SetJSONContentType() *HTTPClient { c.client.SetHeader("Content-Type", "application/json") return c } // SetHeader 设置请求头 func (c *HTTPClient) SetHeader(key, value string) *HTTPClient { c.client.SetHeader(key, value) return c } // SetHeaders 批量设置请求头 func (c *HTTPClient) SetHeaders(headers map[string]string) *HTTPClient { c.client.SetHeaders(headers) return c } // SetAuthHeaders 设置认证相关的headers func (c *HTTPClient) SetAuthHeaders(token string) *HTTPClient { return c.SetJSONContentType().SetBearerToken(token) } // SetBasicAuthHeaders 设置Basic认证相关的headers func (c *HTTPClient) SetBasicAuthHeaders(username, password string) *HTTPClient { return c.SetJSONContentType().SetBasicAuth(username, password) } // Post 发送POST请求(在请求级别设置认证信息,避免多用户相互影响) func (c *HTTPClient) Post(url string, data interface{}) (*resty.Response, error) { return c.client.R().SetBody(data).Post(url) } // PostWithResult 发送POST请求并解析结果 func (c *HTTPClient) PostWithResult(url string, data interface{}, result interface{}) (*resty.Response, error) { return c.client.R().SetBody(data).SetResult(result).Post(url) } // PostWithAuth 发送带Bearer Token的POST请求(推荐用于多用户场景) func (c *HTTPClient) PostWithAuth(url string, data interface{}, token string, result interface{}) (*resty.Response, error) { req := c.client.R().SetBody(data) if token != "" { req.SetHeader("Authorization", "Bearer "+token) } if result != nil { req.SetResult(result) } return req.Post(url) } // Get 发送GET请求 func (c *HTTPClient) Get(url string) (*resty.Response, error) { return c.client.R().Get(url) } // GetWithResult 发送GET请求并解析结果 func (c *HTTPClient) GetWithResult(url string, result interface{}) (*resty.Response, error) { return c.client.R().SetResult(result).Get(url) } // GetWithAuth 发送带Bearer Token的GET请求(推荐用于多用户场景) func (c *HTTPClient) GetWithAuth(url string, token string, result interface{}) (*resty.Response, error) { req := c.client.R() if token != "" { req.SetHeader("Authorization", "Bearer "+token) } if result != nil { req.SetResult(result) } return req.Get(url) } // Put 发送PUT请求 func (c *HTTPClient) Put(url string, data interface{}) (*resty.Response, error) { return c.client.R().SetBody(data).Put(url) } // PutWithResult 发送PUT请求并解析结果 func (c *HTTPClient) PutWithResult(url string, data interface{}, result interface{}) (*resty.Response, error) { return c.client.R().SetBody(data).SetResult(result).Put(url) } // Delete 发送DELETE请求 func (c *HTTPClient) Delete(url string) (*resty.Response, error) { return c.client.R().Delete(url) } // DeleteWithResult 发送DELETE请求并解析结果 func (c *HTTPClient) DeleteWithResult(url string, result interface{}) (*resty.Response, error) { return c.client.R().SetResult(result).Delete(url) } // ==================== 便捷函数(修正版) ==================== // PostJSON 便捷函数:直接发送POST请求 func PostJSON(url string, data interface{}, result interface{}) (*resty.Response, error) { client, err := CreateClient() if err != nil { return nil, err } if result != nil { return client.PostWithResult(url, data, result) } return client.Post(url, data) } // PostJSONWithBearerToken 便捷函数:使用Bearer Token发送POST请求 func PostJSONWithBearerToken(token, url string, data interface{}, result interface{}) (*resty.Response, error) { client, err := CreateClient() if err != nil { return nil, err } return client.PostWithAuth(url, data, token, result) } // PostJSONWithBasicAuth 便捷函数:使用Basic认证发送POST请求 func PostJSONWithBasicAuth(username, password, url string, data interface{}, result interface{}) (*resty.Response, error) { client, err := CreateClient() if err != nil { return nil, err } // 为这个特定请求设置Basic Auth req := client.client.R().SetBody(data) if username != "" && password != "" { auth := username + ":" + password token := base64.StdEncoding.EncodeToString([]byte(auth)) req.SetHeader("Authorization", "Basic "+token) } if result != nil { req.SetResult(result) } return req.Post(url) } // GetJSON 便捷函数:直接发送GET请求 func GetJSON(url string, result interface{}) (*resty.Response, error) { client, err := CreateClient() if err != nil { return nil, err } if result != nil { return client.GetWithResult(url, result) } return client.Get(url) } // GetJSONWithBearerToken 便捷函数:使用Bearer Token发送GET请求 func GetJSONWithBearerToken(token, url string, result interface{}) (*resty.Response, error) { client, err := CreateClient() if err != nil { return nil, err } return client.GetWithAuth(url, token, result) } // GetJSONWithBasicAuth 便捷函数:使用Basic认证发送GET请求 func GetJSONWithBasicAuth(username, password, url string, result interface{}) (*resty.Response, error) { client, err := CreateClient() if err != nil { return nil, err } // 为这个特定请求设置Basic Auth req := client.client.R() if username != "" && password != "" { auth := username + ":" + password token := base64.StdEncoding.EncodeToString([]byte(auth)) req.SetHeader("Authorization", "Basic "+token) } if result != nil { req.SetResult(result) } return req.Get(url) }