github.com/wangyougui/gf/v2@v2.6.5/net/gclient/gclient.go (about)

     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/wangyougui/gf.
     6  
     7  // Package gclient provides convenient http client functionalities.
     8  package gclient
     9  
    10  import (
    11  	"crypto/rand"
    12  	"crypto/tls"
    13  	"fmt"
    14  	"net/http"
    15  	"os"
    16  	"time"
    17  
    18  	"github.com/wangyougui/gf/v2"
    19  	"github.com/wangyougui/gf/v2/errors/gerror"
    20  	"github.com/wangyougui/gf/v2/net/gsel"
    21  	"github.com/wangyougui/gf/v2/net/gsvc"
    22  	"github.com/wangyougui/gf/v2/os/gfile"
    23  )
    24  
    25  // Client is the HTTP client for HTTP request management.
    26  type Client struct {
    27  	http.Client                         // Underlying HTTP Client.
    28  	header            map[string]string // Custom header map.
    29  	cookies           map[string]string // Custom cookie map.
    30  	prefix            string            // Prefix for request.
    31  	authUser          string            // HTTP basic authentication: user.
    32  	authPass          string            // HTTP basic authentication: pass.
    33  	retryCount        int               // Retry count when request fails.
    34  	noUrlEncode       bool              // No url encoding for request parameters.
    35  	retryInterval     time.Duration     // Retry interval when request fails.
    36  	middlewareHandler []HandlerFunc     // Interceptor handlers
    37  	discovery         gsvc.Discovery    // Discovery for service.
    38  	builder           gsel.Builder      // Builder for request balance.
    39  }
    40  
    41  const (
    42  	httpProtocolName          = `http`
    43  	httpParamFileHolder       = `@file:`
    44  	httpRegexParamJson        = `^[\w\[\]]+=.+`
    45  	httpRegexHeaderRaw        = `^([\w\-]+):\s*(.+)`
    46  	httpHeaderHost            = `Host`
    47  	httpHeaderCookie          = `Cookie`
    48  	httpHeaderUserAgent       = `User-Agent`
    49  	httpHeaderContentType     = `Content-Type`
    50  	httpHeaderContentTypeJson = `application/json`
    51  	httpHeaderContentTypeXml  = `application/xml`
    52  	httpHeaderContentTypeForm = `application/x-www-form-urlencoded`
    53  )
    54  
    55  var (
    56  	hostname, _        = os.Hostname()
    57  	defaultClientAgent = fmt.Sprintf(`GClient %s at %s`, gf.VERSION, hostname)
    58  )
    59  
    60  // New creates and returns a new HTTP client object.
    61  func New() *Client {
    62  	c := &Client{
    63  		Client: http.Client{
    64  			Transport: &http.Transport{
    65  				// No validation for https certification of the server in default.
    66  				TLSClientConfig: &tls.Config{
    67  					InsecureSkipVerify: true,
    68  				},
    69  				DisableKeepAlives: true,
    70  			},
    71  		},
    72  		header:    make(map[string]string),
    73  		cookies:   make(map[string]string),
    74  		builder:   gsel.GetBuilder(),
    75  		discovery: gsvc.GetRegistry(),
    76  	}
    77  	c.header[httpHeaderUserAgent] = defaultClientAgent
    78  	// It enables OpenTelemetry for client in default.
    79  	c.Use(internalMiddlewareTracing, internalMiddlewareDiscovery)
    80  	return c
    81  }
    82  
    83  // Clone deeply clones current client and returns a new one.
    84  func (c *Client) Clone() *Client {
    85  	newClient := New()
    86  	*newClient = *c
    87  	if len(c.header) > 0 {
    88  		newClient.header = make(map[string]string)
    89  		for k, v := range c.header {
    90  			newClient.header[k] = v
    91  		}
    92  	}
    93  	if len(c.cookies) > 0 {
    94  		newClient.cookies = make(map[string]string)
    95  		for k, v := range c.cookies {
    96  			newClient.cookies[k] = v
    97  		}
    98  	}
    99  	return newClient
   100  }
   101  
   102  // LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files.
   103  func LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) {
   104  	crtPath, err := gfile.Search(crtFile)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	keyPath, err := gfile.Search(keyFile)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	crt, err := tls.LoadX509KeyPair(crtPath, keyPath)
   113  	if err != nil {
   114  		err = gerror.Wrapf(err, `tls.LoadX509KeyPair failed for certFile "%s", keyFile "%s"`, crtPath, keyPath)
   115  		return nil, err
   116  	}
   117  	tlsConfig := &tls.Config{}
   118  	tlsConfig.Certificates = []tls.Certificate{crt}
   119  	tlsConfig.Time = time.Now
   120  	tlsConfig.Rand = rand.Reader
   121  	return tlsConfig, nil
   122  }