Açıklama Yok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

http_factory.go 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. package http
  2. import (
  3. "encoding/base64"
  4. "net/http"
  5. "sync"
  6. "time"
  7. "git.x2erp.com/qdy/go-base/config"
  8. "github.com/go-resty/resty/v2"
  9. )
  10. // HTTPClient 简化的HTTP客户端
  11. type HTTPClient struct {
  12. client *resty.Client
  13. }
  14. // HTTPFactory HTTP客户端工厂
  15. type HTTPFactory struct {
  16. config config.IConfig
  17. client *resty.Client
  18. }
  19. var (
  20. httpFactoryInstance *HTTPFactory
  21. httpFactoryOnce sync.Once
  22. httpFactoryInitErr error
  23. )
  24. // GetHTTPFactory 获取HTTP工厂单例实例
  25. func GetHTTPFactory() (*HTTPFactory, error) {
  26. httpFactoryOnce.Do(func() {
  27. cfg := config.GetConfig()
  28. httpConfig := cfg.GetHTTPConfig()
  29. // 创建共享的resty客户端(线程安全)
  30. client := resty.New()
  31. client.SetTimeout(time.Duration(httpConfig.Timeout) * time.Second)
  32. client.SetTransport(&http.Transport{
  33. MaxIdleConns: httpConfig.MaxIdleConns,
  34. MaxIdleConnsPerHost: httpConfig.MaxIdleConnsPerHost,
  35. IdleConnTimeout: time.Duration(httpConfig.IdleConnTimeout) * time.Second,
  36. MaxConnsPerHost: httpConfig.MaxConnsPerHost,
  37. DisableCompression: httpConfig.DisableCompression,
  38. DisableKeepAlives: httpConfig.DisableKeepAlives,
  39. })
  40. // 设置默认headers
  41. client.SetHeaders(map[string]string{
  42. "Content-Type": "application/json",
  43. "Accept": "application/json",
  44. })
  45. httpFactoryInstance = &HTTPFactory{
  46. config: cfg,
  47. client: client,
  48. }
  49. })
  50. return httpFactoryInstance, httpFactoryInitErr
  51. }
  52. // CreateClient 创建HTTP客户端包装器(共享底层resty.Client)
  53. func (f *HTTPFactory) CreateClient() *HTTPClient {
  54. return &HTTPClient{
  55. client: f.client, // 共享同一个线程安全的客户端
  56. }
  57. }
  58. // GetUnderlyingClient 获取底层resty客户端(用于特殊场景)
  59. func (f *HTTPFactory) GetUnderlyingClient() *resty.Client {
  60. if f == nil {
  61. return nil
  62. }
  63. return f.client
  64. }
  65. // CreateClient 全局便捷函数:创建HTTP客户端
  66. func CreateClient() (*HTTPClient, error) {
  67. factory, err := GetHTTPFactory()
  68. if err != nil {
  69. return nil, err
  70. }
  71. return factory.CreateClient(), nil
  72. }
  73. // GetInitError 获取初始化错误(如果有)
  74. func GetInitError() error {
  75. return httpFactoryInitErr
  76. }
  77. // ==================== HTTPClient 方法 ====================
  78. // SetAuthToken 设置认证token(请求级别)
  79. func (c *HTTPClient) SetAuthToken(token string) *HTTPClient {
  80. // 注意:这里设置的是客户端级别的token,会影响所有使用该客户端的请求
  81. // 对于多用户场景,应该在请求级别设置
  82. c.client.SetAuthToken(token)
  83. return c
  84. }
  85. // SetBearerToken 设置Bearer Token认证头(请求级别)
  86. func (c *HTTPClient) SetBearerToken(token string) *HTTPClient {
  87. if token != "" {
  88. c.client.SetHeader("Authorization", "Bearer "+token)
  89. } else {
  90. c.client.Header.Del("Authorization")
  91. }
  92. return c
  93. }
  94. // SetBasicAuth 设置Basic认证头(请求级别)
  95. func (c *HTTPClient) SetBasicAuth(username, password string) *HTTPClient {
  96. if username != "" && password != "" {
  97. auth := username + ":" + password
  98. token := base64.StdEncoding.EncodeToString([]byte(auth))
  99. c.client.SetHeader("Authorization", "Basic "+token)
  100. } else {
  101. c.client.Header.Del("Authorization")
  102. }
  103. return c
  104. }
  105. // SetJSONContentType 设置Content-Type为application/json
  106. func (c *HTTPClient) SetJSONContentType() *HTTPClient {
  107. c.client.SetHeader("Content-Type", "application/json")
  108. return c
  109. }
  110. // SetHeader 设置请求头
  111. func (c *HTTPClient) SetHeader(key, value string) *HTTPClient {
  112. c.client.SetHeader(key, value)
  113. return c
  114. }
  115. // SetHeaders 批量设置请求头
  116. func (c *HTTPClient) SetHeaders(headers map[string]string) *HTTPClient {
  117. c.client.SetHeaders(headers)
  118. return c
  119. }
  120. // SetAuthHeaders 设置认证相关的headers
  121. func (c *HTTPClient) SetAuthHeaders(token string) *HTTPClient {
  122. return c.SetJSONContentType().SetBearerToken(token)
  123. }
  124. // SetBasicAuthHeaders 设置Basic认证相关的headers
  125. func (c *HTTPClient) SetBasicAuthHeaders(username, password string) *HTTPClient {
  126. return c.SetJSONContentType().SetBasicAuth(username, password)
  127. }
  128. // Post 发送POST请求(在请求级别设置认证信息,避免多用户相互影响)
  129. func (c *HTTPClient) Post(url string, data interface{}) (*resty.Response, error) {
  130. return c.client.R().SetBody(data).Post(url)
  131. }
  132. // PostWithResult 发送POST请求并解析结果
  133. func (c *HTTPClient) PostWithResult(url string, data interface{}, result interface{}) (*resty.Response, error) {
  134. return c.client.R().SetBody(data).SetResult(result).Post(url)
  135. }
  136. // PostWithAuth 发送带Bearer Token的POST请求(推荐用于多用户场景)
  137. func (c *HTTPClient) PostWithAuth(url string, data interface{}, token string, result interface{}) (*resty.Response, error) {
  138. req := c.client.R().SetBody(data)
  139. if token != "" {
  140. req.SetHeader("Authorization", "Bearer "+token)
  141. }
  142. if result != nil {
  143. req.SetResult(result)
  144. }
  145. return req.Post(url)
  146. }
  147. // Get 发送GET请求
  148. func (c *HTTPClient) Get(url string) (*resty.Response, error) {
  149. return c.client.R().Get(url)
  150. }
  151. // GetWithResult 发送GET请求并解析结果
  152. func (c *HTTPClient) GetWithResult(url string, result interface{}) (*resty.Response, error) {
  153. return c.client.R().SetResult(result).Get(url)
  154. }
  155. // GetWithAuth 发送带Bearer Token的GET请求(推荐用于多用户场景)
  156. func (c *HTTPClient) GetWithAuth(url string, token string, result interface{}) (*resty.Response, error) {
  157. req := c.client.R()
  158. if token != "" {
  159. req.SetHeader("Authorization", "Bearer "+token)
  160. }
  161. if result != nil {
  162. req.SetResult(result)
  163. }
  164. return req.Get(url)
  165. }
  166. // Put 发送PUT请求
  167. func (c *HTTPClient) Put(url string, data interface{}) (*resty.Response, error) {
  168. return c.client.R().SetBody(data).Put(url)
  169. }
  170. // PutWithResult 发送PUT请求并解析结果
  171. func (c *HTTPClient) PutWithResult(url string, data interface{}, result interface{}) (*resty.Response, error) {
  172. return c.client.R().SetBody(data).SetResult(result).Put(url)
  173. }
  174. // Delete 发送DELETE请求
  175. func (c *HTTPClient) Delete(url string) (*resty.Response, error) {
  176. return c.client.R().Delete(url)
  177. }
  178. // DeleteWithResult 发送DELETE请求并解析结果
  179. func (c *HTTPClient) DeleteWithResult(url string, result interface{}) (*resty.Response, error) {
  180. return c.client.R().SetResult(result).Delete(url)
  181. }
  182. // ==================== 便捷函数(修正版) ====================
  183. // PostJSON 便捷函数:直接发送POST请求
  184. func PostJSON(url string, data interface{}, result interface{}) (*resty.Response, error) {
  185. client, err := CreateClient()
  186. if err != nil {
  187. return nil, err
  188. }
  189. if result != nil {
  190. return client.PostWithResult(url, data, result)
  191. }
  192. return client.Post(url, data)
  193. }
  194. // PostJSONWithBearerToken 便捷函数:使用Bearer Token发送POST请求
  195. func PostJSONWithBearerToken(token, url string, data interface{}, result interface{}) (*resty.Response, error) {
  196. client, err := CreateClient()
  197. if err != nil {
  198. return nil, err
  199. }
  200. return client.PostWithAuth(url, data, token, result)
  201. }
  202. // PostJSONWithBasicAuth 便捷函数:使用Basic认证发送POST请求
  203. func PostJSONWithBasicAuth(username, password, url string, data interface{}, result interface{}) (*resty.Response, error) {
  204. client, err := CreateClient()
  205. if err != nil {
  206. return nil, err
  207. }
  208. // 为这个特定请求设置Basic Auth
  209. req := client.client.R().SetBody(data)
  210. if username != "" && password != "" {
  211. auth := username + ":" + password
  212. token := base64.StdEncoding.EncodeToString([]byte(auth))
  213. req.SetHeader("Authorization", "Basic "+token)
  214. }
  215. if result != nil {
  216. req.SetResult(result)
  217. }
  218. return req.Post(url)
  219. }
  220. // GetJSON 便捷函数:直接发送GET请求
  221. func GetJSON(url string, result interface{}) (*resty.Response, error) {
  222. client, err := CreateClient()
  223. if err != nil {
  224. return nil, err
  225. }
  226. if result != nil {
  227. return client.GetWithResult(url, result)
  228. }
  229. return client.Get(url)
  230. }
  231. // GetJSONWithBearerToken 便捷函数:使用Bearer Token发送GET请求
  232. func GetJSONWithBearerToken(token, url string, result interface{}) (*resty.Response, error) {
  233. client, err := CreateClient()
  234. if err != nil {
  235. return nil, err
  236. }
  237. return client.GetWithAuth(url, token, result)
  238. }
  239. // GetJSONWithBasicAuth 便捷函数:使用Basic认证发送GET请求
  240. func GetJSONWithBasicAuth(username, password, url string, result interface{}) (*resty.Response, error) {
  241. client, err := CreateClient()
  242. if err != nil {
  243. return nil, err
  244. }
  245. // 为这个特定请求设置Basic Auth
  246. req := client.client.R()
  247. if username != "" && password != "" {
  248. auth := username + ":" + password
  249. token := base64.StdEncoding.EncodeToString([]byte(auth))
  250. req.SetHeader("Authorization", "Basic "+token)
  251. }
  252. if result != nil {
  253. req.SetResult(result)
  254. }
  255. return req.Get(url)
  256. }