client.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package client
  7. import (
  8. "context"
  9. "crypto/rand"
  10. "crypto/tls"
  11. "fmt"
  12. "github.com/gogf/gf"
  13. "github.com/gogf/gf/errors/gcode"
  14. "github.com/gogf/gf/errors/gerror"
  15. "github.com/gogf/gf/os/gfile"
  16. "github.com/gogf/gf/text/gstr"
  17. "golang.org/x/net/proxy"
  18. "net"
  19. "net/http"
  20. "net/http/cookiejar"
  21. "net/url"
  22. "strings"
  23. "time"
  24. "github.com/gogf/gf/text/gregex"
  25. )
  26. // Client is the HTTP client for HTTP request management.
  27. type Client struct {
  28. http.Client // Underlying HTTP Client.
  29. ctx context.Context // Context for each request.
  30. dump bool // Mark this request will be dumped.
  31. parent *Client // Parent http client, this is used for chaining operations.
  32. header map[string]string // Custom header map.
  33. cookies map[string]string // Custom cookie map.
  34. prefix string // Prefix for request.
  35. authUser string // HTTP basic authentication: user.
  36. authPass string // HTTP basic authentication: pass.
  37. retryCount int // Retry count when request fails.
  38. retryInterval time.Duration // Retry interval when request fails.
  39. middlewareHandler []HandlerFunc // Interceptor handlers
  40. }
  41. var (
  42. defaultClientAgent = fmt.Sprintf(`GoFrameHTTPClient %s`, gf.VERSION)
  43. )
  44. // New creates and returns a new HTTP client object.
  45. func New() *Client {
  46. client := &Client{
  47. Client: http.Client{
  48. Transport: &http.Transport{
  49. // No validation for https certification of the server in default.
  50. TLSClientConfig: &tls.Config{
  51. InsecureSkipVerify: true,
  52. },
  53. DisableKeepAlives: true,
  54. },
  55. },
  56. header: make(map[string]string),
  57. cookies: make(map[string]string),
  58. }
  59. client.header["User-Agent"] = defaultClientAgent
  60. return client
  61. }
  62. // Clone deeply clones current client and returns a new one.
  63. func (c *Client) Clone() *Client {
  64. newClient := New()
  65. *newClient = *c
  66. newClient.header = make(map[string]string)
  67. newClient.cookies = make(map[string]string)
  68. for k, v := range c.header {
  69. newClient.header[k] = v
  70. }
  71. for k, v := range c.cookies {
  72. newClient.cookies[k] = v
  73. }
  74. return newClient
  75. }
  76. // SetBrowserMode enables browser mode of the client.
  77. // When browser mode is enabled, it automatically saves and sends cookie content
  78. // from and to server.
  79. func (c *Client) SetBrowserMode(enabled bool) *Client {
  80. if enabled {
  81. jar, _ := cookiejar.New(nil)
  82. c.Jar = jar
  83. }
  84. return c
  85. }
  86. // SetHeader sets a custom HTTP header pair for the client.
  87. func (c *Client) SetHeader(key, value string) *Client {
  88. c.header[key] = value
  89. return c
  90. }
  91. // SetHeaderMap sets custom HTTP headers with map.
  92. func (c *Client) SetHeaderMap(m map[string]string) *Client {
  93. for k, v := range m {
  94. c.header[k] = v
  95. }
  96. return c
  97. }
  98. // SetAgent sets the User-Agent header for client.
  99. func (c *Client) SetAgent(agent string) *Client {
  100. c.header["User-Agent"] = agent
  101. return c
  102. }
  103. // SetContentType sets HTTP content type for the client.
  104. func (c *Client) SetContentType(contentType string) *Client {
  105. c.header["Content-Type"] = contentType
  106. return c
  107. }
  108. // SetHeaderRaw sets custom HTTP header using raw string.
  109. func (c *Client) SetHeaderRaw(headers string) *Client {
  110. for _, line := range gstr.SplitAndTrim(headers, "\n") {
  111. array, _ := gregex.MatchString(`^([\w\-]+):\s*(.+)`, line)
  112. if len(array) >= 3 {
  113. c.header[array[1]] = array[2]
  114. }
  115. }
  116. return c
  117. }
  118. // SetCookie sets a cookie pair for the client.
  119. func (c *Client) SetCookie(key, value string) *Client {
  120. c.cookies[key] = value
  121. return c
  122. }
  123. // SetDump enables/disables dump feature for this request.
  124. func (c *Client) SetDump(dump bool) *Client {
  125. c.dump = dump
  126. return c
  127. }
  128. // SetCookieMap sets cookie items with map.
  129. func (c *Client) SetCookieMap(m map[string]string) *Client {
  130. for k, v := range m {
  131. c.cookies[k] = v
  132. }
  133. return c
  134. }
  135. // SetPrefix sets the request server URL prefix.
  136. func (c *Client) SetPrefix(prefix string) *Client {
  137. c.prefix = prefix
  138. return c
  139. }
  140. // SetTimeout sets the request timeout for the client.
  141. func (c *Client) SetTimeout(t time.Duration) *Client {
  142. c.Client.Timeout = t
  143. return c
  144. }
  145. // SetBasicAuth sets HTTP basic authentication information for the client.
  146. func (c *Client) SetBasicAuth(user, pass string) *Client {
  147. c.authUser = user
  148. c.authPass = pass
  149. return c
  150. }
  151. // SetCtx sets context for each request of this client.
  152. func (c *Client) SetCtx(ctx context.Context) *Client {
  153. c.ctx = ctx
  154. return c
  155. }
  156. // SetRetry sets retry count and interval.
  157. func (c *Client) SetRetry(retryCount int, retryInterval time.Duration) *Client {
  158. c.retryCount = retryCount
  159. c.retryInterval = retryInterval
  160. return c
  161. }
  162. // SetRedirectLimit limit the number of jumps
  163. func (c *Client) SetRedirectLimit(redirectLimit int) *Client {
  164. c.CheckRedirect = func(req *http.Request, via []*http.Request) error {
  165. if len(via) >= redirectLimit {
  166. return http.ErrUseLastResponse
  167. }
  168. return nil
  169. }
  170. return c
  171. }
  172. // SetProxy set proxy for the client.
  173. // This func will do nothing when the parameter `proxyURL` is empty or in wrong pattern.
  174. // The correct pattern is like `http://USER:PASSWORD@IP:PORT` or `socks5://USER:PASSWORD@IP:PORT`.
  175. // Only `http` and `socks5` proxies are supported currently.
  176. func (c *Client) SetProxy(proxyURL string) {
  177. if strings.TrimSpace(proxyURL) == "" {
  178. return
  179. }
  180. _proxy, err := url.Parse(proxyURL)
  181. if err != nil {
  182. return
  183. }
  184. if _proxy.Scheme == "http" {
  185. if v, ok := c.Transport.(*http.Transport); ok {
  186. v.Proxy = http.ProxyURL(_proxy)
  187. }
  188. } else {
  189. var auth = &proxy.Auth{}
  190. user := _proxy.User.Username()
  191. if user != "" {
  192. auth.User = user
  193. password, hasPassword := _proxy.User.Password()
  194. if hasPassword && password != "" {
  195. auth.Password = password
  196. }
  197. } else {
  198. auth = nil
  199. }
  200. // refer to the source code, error is always nil
  201. dialer, err := proxy.SOCKS5(
  202. "tcp",
  203. _proxy.Host,
  204. auth,
  205. &net.Dialer{
  206. Timeout: c.Client.Timeout,
  207. KeepAlive: c.Client.Timeout,
  208. },
  209. )
  210. if err != nil {
  211. return
  212. }
  213. if v, ok := c.Transport.(*http.Transport); ok {
  214. v.DialContext = func(ctx context.Context, network, addr string) (conn net.Conn, e error) {
  215. return dialer.Dial(network, addr)
  216. }
  217. }
  218. //c.SetTimeout(10*time.Second)
  219. }
  220. }
  221. // SetTLSKeyCrt sets the certificate and key file for TLS configuration of client.
  222. func (c *Client) SetTLSKeyCrt(crtFile, keyFile string) error {
  223. tlsConfig, err := LoadKeyCrt(crtFile, keyFile)
  224. if err != nil {
  225. return gerror.WrapCode(gcode.CodeInternalError, err, "LoadKeyCrt failed")
  226. }
  227. if v, ok := c.Transport.(*http.Transport); ok {
  228. tlsConfig.InsecureSkipVerify = true
  229. v.TLSClientConfig = tlsConfig
  230. return nil
  231. }
  232. return gerror.NewCode(gcode.CodeInternalError, `cannot set TLSClientConfig for custom Transport of the client`)
  233. }
  234. // SetTLSConfig sets the TLS configuration of client.
  235. func (c *Client) SetTLSConfig(tlsConfig *tls.Config) error {
  236. if v, ok := c.Transport.(*http.Transport); ok {
  237. v.TLSClientConfig = tlsConfig
  238. return nil
  239. }
  240. return gerror.NewCode(gcode.CodeInternalError, `cannot set TLSClientConfig for custom Transport of the client`)
  241. }
  242. // LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files.
  243. func LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) {
  244. crtPath, err := gfile.Search(crtFile)
  245. if err != nil {
  246. return nil, err
  247. }
  248. keyPath, err := gfile.Search(keyFile)
  249. if err != nil {
  250. return nil, err
  251. }
  252. crt, err := tls.LoadX509KeyPair(crtPath, keyPath)
  253. if err != nil {
  254. return nil, err
  255. }
  256. tlsConfig := &tls.Config{}
  257. tlsConfig.Certificates = []tls.Certificate{crt}
  258. tlsConfig.Time = time.Now
  259. tlsConfig.Rand = rand.Reader
  260. return tlsConfig, nil
  261. }