- 新增随机字符串生成函数,支持不同模式(字母、数字、字母数字、字母十六进制) -重构 RandStringBytes 函数,使用新的随机字符串生成逻辑 - 添加 MakeTraceId 函数,用于生成追踪ID - 更新 Client 的 GetRefererHeader 方法,自动添加追踪ID
		
			
				
	
	
		
			397 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			397 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package sdk
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"context"
 | |
| 	"crypto/tls"
 | |
| 	"fmt"
 | |
| 	"github.com/json-iterator/go/extra"
 | |
| 	"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth"
 | |
| 	"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials"
 | |
| 	"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
 | |
| 	"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses"
 | |
| 	"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"net/http/httputil"
 | |
| 	"net/url"
 | |
| 	"os"
 | |
| 	"regexp"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| var Version = "0.0.1"
 | |
| var defaultConnectTimeout = 5 * time.Second
 | |
| var defaultReadTimeout = 10 * time.Second
 | |
| var defaultDomain = ".gaore.com"
 | |
| var DefaultUserAgent = fmt.Sprintf("GaoreGoSdk (%s;%s) Golang/%s Core/%s", runtime.GOOS, runtime.GOARCH, strings.Trim(runtime.Version(), "go"), Version)
 | |
| 
 | |
| var debug utils.Debug
 | |
| 
 | |
| func init() {
 | |
| 	debug = utils.Init("sdk")
 | |
| }
 | |
| 
 | |
| type Client struct {
 | |
| 	Host           string
 | |
| 	httpClient     *http.Client
 | |
| 	isInsecure     bool
 | |
| 	signer         auth.Signer
 | |
| 	readTimeout    time.Duration
 | |
| 	connectTimeout time.Duration
 | |
| 	config         *Config
 | |
| 	httpProxy      string
 | |
| 	httpsProxy     string
 | |
| 	noProxy        string
 | |
| 
 | |
| 	header *requests.RefererHeader
 | |
| }
 | |
| 
 | |
| func (c *Client) SetRefererHeader(header *requests.RefererHeader) {
 | |
| 	c.header = header
 | |
| }
 | |
| 
 | |
| func (c *Client) GetRefererHeader() map[string]string {
 | |
| 	var header *requests.RefererHeader
 | |
| 	if c.header == nil {
 | |
| 		header = &requests.RefererHeader{
 | |
| 			TraceId: utils.MakeTraceId(),
 | |
| 		}
 | |
| 	} else {
 | |
| 		header = c.header
 | |
| 	}
 | |
| 	return map[string]string{
 | |
| 		"Referer":     header.Referer,
 | |
| 		"Traceparent": header.TraceId,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (client *Client) GetNoProxy() string {
 | |
| 	return client.noProxy
 | |
| }
 | |
| 
 | |
| func (client *Client) SetNoProxy(noProxy string) {
 | |
| 	client.noProxy = noProxy
 | |
| }
 | |
| 
 | |
| func (client *Client) GetHttpsProxy() string {
 | |
| 	return client.httpsProxy
 | |
| }
 | |
| 
 | |
| func (client *Client) SetHttpsProxy(httpsProxy string) {
 | |
| 	client.httpsProxy = httpsProxy
 | |
| }
 | |
| 
 | |
| func (client *Client) SetHttpProxy(httpProxy string) {
 | |
| 	client.httpProxy = httpProxy
 | |
| }
 | |
| 
 | |
| func (client *Client) GetHttpProxy() string {
 | |
| 	return client.httpProxy
 | |
| }
 | |
| 
 | |
| func (client *Client) GetHTTPSInsecure() bool {
 | |
| 	return client.isInsecure
 | |
| }
 | |
| 
 | |
| func (client *Client) InitClientConfig() (config *Config) {
 | |
| 	if client.config != nil {
 | |
| 		return client.config
 | |
| 	} else {
 | |
| 		return NewConfig()
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| func (client *Client) Init() (err error) {
 | |
| 	return client.InitWithAccessKey("", "", "")
 | |
| }
 | |
| 
 | |
| func (client *Client) InitWithAccessKey(accessKeyId, accessKeySecret, accessKeyFrom string) (err error) {
 | |
| 	config := client.InitWithConfig()
 | |
| 	var credential auth.Credential
 | |
| 	if accessKeyId != "" {
 | |
| 		credential = &credentials.BaseCredential{
 | |
| 			AccessKeyId:     accessKeyId,
 | |
| 			AccessKeySecret: accessKeySecret,
 | |
| 			AccessKeyFrom:   accessKeyFrom,
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return client.InitWithOptions(config, credential)
 | |
| }
 | |
| 
 | |
| func (client *Client) InitWithAliAppcode(accessKeyId, accessKeySecret string, env ...string) (err error) {
 | |
| 	config := client.InitWithConfig()
 | |
| 	credential := credentials.NewAliAppcodeCredential(accessKeyId, accessKeySecret)
 | |
| 
 | |
| 	if len(env) > 0 {
 | |
| 		config.Env = env[0]
 | |
| 	}
 | |
| 
 | |
| 	return client.InitWithOptions(config, credential)
 | |
| }
 | |
| 
 | |
| func (client *Client) InitWithStsToken(accessKeyId, accessKeySecret, accessKeyFrom string) (err error) {
 | |
| 	config := client.InitWithConfig()
 | |
| 	credential := &credentials.StdTokenCredential{
 | |
| 		AccessKeyId:     accessKeyId,
 | |
| 		AccessKeySecret: accessKeySecret,
 | |
| 		AccessKeyFrom:   accessKeyFrom,
 | |
| 	}
 | |
| 	return client.InitWithOptions(config, credential)
 | |
| }
 | |
| 
 | |
| func (client *Client) InitWithOptions(config *Config, credential auth.Credential) (err error) {
 | |
| 	client.httpClient = &http.Client{}
 | |
| 	client.config = config
 | |
| 
 | |
| 	if config.Transport != nil {
 | |
| 		client.httpClient.Transport = config.Transport
 | |
| 	} else if config.HttpTransport != nil {
 | |
| 		client.httpClient.Transport = config.HttpTransport
 | |
| 	}
 | |
| 
 | |
| 	if config.Timeout > 0 {
 | |
| 		client.httpClient.Timeout = config.Timeout
 | |
| 	}
 | |
| 	if credential != nil {
 | |
| 		client.signer, err = auth.NewSignerWithCredential(credential, client.ProcessCommonRequestWithSigner)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (client *Client) InitWithConfig() (config *Config) {
 | |
| 	if client.config != nil {
 | |
| 		return client.config
 | |
| 	} else {
 | |
| 		return NewConfig()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (client *Client) ProcessCommonRequestWithSigner(request *requests.CommonRequest, signerInterface interface{}) (response *responses.CommonResponse, err error) {
 | |
| 	if signer, isSigner := signerInterface.(auth.Signer); isSigner {
 | |
| 		response = responses.NewCommonResponse()
 | |
| 		err = client.DoActionWithSigner(request, response, signer)
 | |
| 		return
 | |
| 	}
 | |
| 	panic("should not be here")
 | |
| }
 | |
| 
 | |
| func Timeout(connectTimeout time.Duration) func(ctx context.Context, net, addr string) (c net.Conn, err error) {
 | |
| 	return func(ctx context.Context, network, address string) (c net.Conn, err error) {
 | |
| 		return (&net.Dialer{
 | |
| 			Timeout:   connectTimeout,
 | |
| 			DualStack: true,
 | |
| 		}).DialContext(ctx, network, address)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (client *Client) setTimeOut(request requests.AcsRequest) {
 | |
| 	readTimeout, connectTimeout := client.getTimeOut(request)
 | |
| 	client.httpClient.Timeout = readTimeout
 | |
| 	if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
 | |
| 		trans.DialContext = Timeout(connectTimeout)
 | |
| 		client.httpClient.Transport = trans
 | |
| 	} else if client.httpClient.Transport == nil {
 | |
| 		client.httpClient.Transport = &http.Transport{
 | |
| 			DialContext: Timeout(connectTimeout),
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (client *Client) getTimeOut(request requests.AcsRequest) (time.Duration, time.Duration) {
 | |
| 	readTimeOut := defaultReadTimeout
 | |
| 	connectTimeOut := defaultConnectTimeout
 | |
| 
 | |
| 	reqReadTimeout := request.GetReadTimeout()
 | |
| 	reqConnectTimeout := request.GetConnectTimeout()
 | |
| 	if reqReadTimeout != 0*time.Millisecond {
 | |
| 		readTimeOut = reqReadTimeout
 | |
| 	} else if client.readTimeout != 0*time.Microsecond {
 | |
| 		readTimeOut = client.readTimeout
 | |
| 	} else if client.httpClient.Timeout != 0 {
 | |
| 		readTimeOut = client.httpClient.Timeout
 | |
| 	}
 | |
| 
 | |
| 	if reqConnectTimeout != 0*time.Microsecond {
 | |
| 		connectTimeOut = reqConnectTimeout
 | |
| 	} else if client.connectTimeout != 0*time.Millisecond {
 | |
| 		connectTimeOut = client.connectTimeout
 | |
| 	}
 | |
| 	return readTimeOut, connectTimeOut
 | |
| }
 | |
| 
 | |
| func (client *Client) getHTTPSInsecure(request requests.AcsRequest) (insecure bool) {
 | |
| 	if request.GetHTTPSInsecure() != nil {
 | |
| 		insecure = *request.GetHTTPSInsecure()
 | |
| 	} else {
 | |
| 		insecure = client.GetHTTPSInsecure()
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (client *Client) DoAction(request requests.AcsRequest, response responses.AcsResponse) (err error) {
 | |
| 	return client.DoActionWithSigner(request, response, nil)
 | |
| }
 | |
| 
 | |
| func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) {
 | |
| 	request.AddHeaders(client.GetRefererHeader())
 | |
| 	httpRequest, err := client.buildRequestWithSigner(request, signer)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	client.setTimeOut(request)
 | |
| 	proxy, err := client.getHttpProxy(httpRequest.URL.Scheme)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	noProxy := client.getNoProxy(httpRequest.URL.Scheme)
 | |
| 	var flag bool
 | |
| 	for _, value := range noProxy {
 | |
| 		if strings.HasPrefix(value, "*") {
 | |
| 			value = fmt.Sprint(".%s", value)
 | |
| 		}
 | |
| 		noProxyReg, err := regexp.Compile(value)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if noProxyReg.MatchString(httpRequest.Host) {
 | |
| 			flag = true
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
 | |
| 		if trans.TLSClientConfig != nil {
 | |
| 			trans.TLSClientConfig.InsecureSkipVerify = client.getHTTPSInsecure(request)
 | |
| 		} else {
 | |
| 			trans.TLSClientConfig = &tls.Config{
 | |
| 				InsecureSkipVerify: client.getHTTPSInsecure(request),
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if proxy != nil && !flag {
 | |
| 			trans.Proxy = http.ProxyURL(proxy)
 | |
| 		}
 | |
| 
 | |
| 		client.httpClient.Transport = trans
 | |
| 	}
 | |
| 
 | |
| 	dump, err := httputil.DumpRequest(httpRequest, true)
 | |
| 	debug("client %s", bytes.NewBuffer(dump).String())
 | |
| 
 | |
| 	var httpResponse *http.Response
 | |
| 	httpResponse, err = hookDo(client.httpClient.Do)(httpRequest)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat())
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (client *Client) buildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (httpRequest *http.Request, err error) {
 | |
| 	// init param
 | |
| 	domain := request.GetDomain()
 | |
| 	if strings.Index(domain.Default, ".") < 0 {
 | |
| 		domain.Default += defaultDomain
 | |
| 		request.SetDomain(domain)
 | |
| 	}
 | |
| 
 | |
| 	if request.GetScheme() == "" {
 | |
| 		request.SetScheme(client.config.Scheme)
 | |
| 	}
 | |
| 
 | |
| 	if request.GetEnv() == "" && client.config.Env != "" {
 | |
| 		request.SetEnv(client.config.Env)
 | |
| 	}
 | |
| 
 | |
| 	err = requests.InitParam(request)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	// build signature
 | |
| 	var finalSigner auth.Signer
 | |
| 	if signer != nil {
 | |
| 		finalSigner = signer
 | |
| 	} else {
 | |
| 		finalSigner = client.signer
 | |
| 	}
 | |
| 	err = auth.Sign(request, finalSigner)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// build request
 | |
| 	requestMethod := request.GetMethod()
 | |
| 	requestUrl := request.BuildUrl()
 | |
| 	body := request.GetBodyReader()
 | |
| 	httpRequest, err = http.NewRequest(requestMethod, requestUrl, body)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	for key, val := range request.GetHeaders() {
 | |
| 		httpRequest.Header[key] = []string{val}
 | |
| 	}
 | |
| 
 | |
| 	if host, isContainsHost := request.GetHeaders()["host"]; isContainsHost {
 | |
| 		httpRequest.Host = host
 | |
| 	}
 | |
| 
 | |
| 	userAgent := DefaultUserAgent
 | |
| 	httpRequest.Header.Set("User-Agent", userAgent)
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (client *Client) getHttpProxy(scheme string) (proxy *url.URL, err error) {
 | |
| 	switch scheme {
 | |
| 	case "https":
 | |
| 		if client.GetHttpsProxy() != "" {
 | |
| 			proxy, err = url.Parse(client.httpsProxy)
 | |
| 		} else if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" {
 | |
| 			proxy, err = url.Parse(rawurl)
 | |
| 		} else if rawurl := os.Getenv("https_proxy"); rawurl != "" {
 | |
| 			proxy, err = url.Parse(rawurl)
 | |
| 		}
 | |
| 	default:
 | |
| 		if client.GetHttpProxy() != "" {
 | |
| 			proxy, err = url.Parse(client.httpProxy)
 | |
| 		} else if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" {
 | |
| 			proxy, err = url.Parse(rawurl)
 | |
| 		} else if rawurl := os.Getenv("http_proxy"); rawurl != "" {
 | |
| 			proxy, err = url.Parse(rawurl)
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (client *Client) getNoProxy(scheme string) []string {
 | |
| 	var urls []string
 | |
| 	if client.GetNoProxy() != "" {
 | |
| 		urls = strings.Split(client.noProxy, ",")
 | |
| 	} else if rawurl := os.Getenv("NO_PROXY"); rawurl != "" {
 | |
| 		urls = strings.Split(rawurl, ",")
 | |
| 	} else if rawurl := os.Getenv("no_proxy"); rawurl != "" {
 | |
| 		urls = strings.Split(rawurl, ",")
 | |
| 	}
 | |
| 	return urls
 | |
| }
 | |
| 
 | |
| func hookDo(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
 | |
| 	return fn
 | |
| }
 | |
| 
 | |
| func init() {
 | |
| 	once := sync.Once{}
 | |
| 	once.Do(func() {
 | |
| 		extra.RegisterFuzzyDecoders()
 | |
| 	})
 | |
| }
 |