refactor(provider): re-implement deployment provider of volcengine and byteplus tos with custom sdk, to lightweight package size

This commit is contained in:
Fu Diwei
2026-06-22 16:32:18 +08:00
committed by RHQYZ
parent c3fc1866c7
commit bc6191e8eb
12 changed files with 370 additions and 48 deletions
-1
View File
@@ -77,7 +77,6 @@ require (
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.3.112
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.3.111
github.com/ucloud/ucloud-sdk-go v0.22.77
github.com/volcengine/ve-tos-golang-sdk/v2 v2.9.5
github.com/volcengine/volc-sdk-golang v1.0.250
github.com/volcengine/volcengine-go-sdk v1.2.35
github.com/wneessen/go-mail v0.7.3
-4
View File
@@ -849,7 +849,6 @@ github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -933,8 +932,6 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri
github.com/ucloud/ucloud-sdk-go v0.22.77 h1:5f54RZhVm4lgQ5RbKnzbk2Ck79XBn/cYRJbZ3zsNogQ=
github.com/ucloud/ucloud-sdk-go v0.22.77/go.mod h1:dyLmFHmUfgb4RZKYQP9IArlvQ2pxzFthfhwxRzOEPIw=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/volcengine/ve-tos-golang-sdk/v2 v2.9.5 h1:6f6C0aTlnPiCH+KRKknf8vxbqqn0aA0J9WhO5mArFfg=
github.com/volcengine/ve-tos-golang-sdk/v2 v2.9.5/go.mod h1:IrjK84IJJTuOZOTMv/P18Ydjy/x+ow7fF7q11jAxXLM=
github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU=
github.com/volcengine/volc-sdk-golang v1.0.250 h1:2/RLIahTgZ57OkNgDV0FpAkvk/4QFMGIuVFTnU26GDs=
github.com/volcengine/volc-sdk-golang v1.0.250/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
@@ -1235,7 +1232,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -4,11 +4,11 @@ import (
"context"
"fmt"
"log/slog"
"github.com/volcengine/ve-tos-golang-sdk/v2/tos"
"net/url"
"github.com/certimate-go/certimate/pkg/core"
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/byteplus-certcenter"
tossdk "github.com/certimate-go/certimate/pkg/sdk3rd/volcengine/tos"
)
type (
@@ -34,7 +34,7 @@ type DeployerConfig struct {
type Deployer struct {
config *DeployerConfig
logger *slog.Logger
sdkClient *tos.ClientV2
sdkClient *tossdk.Client
sdkCertmgr core.Certmgr
}
@@ -45,7 +45,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) {
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
}
client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region)
client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region, config.Bucket)
if err != nil {
return nil, fmt.Errorf("could not create client: %w", err)
}
@@ -96,16 +96,14 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
// 设置自定义域名
// REF: https://docs.byteplus.com/en/docs/tos/Putbucketcustomdomain
// REF: https://docs.byteplus.com/en/docs/tos/Manage-custom-domain-names-go-sdk
putBucketCustomDomainReq := &tos.PutBucketCustomDomainInput{
Bucket: d.config.Bucket,
Rule: tos.CustomDomainRule{
putBucketCustomDomainReq := &tossdk.PutBucketCustomDomainRequest{
CustomDomainRule: &tossdk.PutBucketCustomDomainRequestCustomDomainRule{
Domain: d.config.Domain,
CertID: upres.CertId,
CertId: upres.CertId,
},
}
putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomain(ctx, putBucketCustomDomainReq)
d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp))
putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomainWithContext(ctx, putBucketCustomDomainReq)
d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.String("params.bucket", d.config.Bucket), slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'tos.PutBucketCustomDomain': %w", err)
}
@@ -113,13 +111,13 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
return &DeployResult{}, nil
}
func createSDKClient(accessKeyId, secretAccessKey, region string) (*tos.ClientV2, error) {
endpoint := fmt.Sprintf("tos-%s.bytepluses.com", region)
func createSDKClient(accessKeyId, secretAccessKey, region, bucket string) (*tossdk.Client, error) {
endpoint := fmt.Sprintf("https://%s.tos-%s.bytepluses.com", url.PathEscape(bucket), url.PathEscape(region))
client, err := tos.NewClientV2(
endpoint,
tos.WithRegion(region),
tos.WithCredentials(tos.NewStaticCredentials(accessKeyId, secretAccessKey)),
client, err := tossdk.NewClient(endpoint,
tossdk.WithAkSk(accessKeyId, secretAccessKey),
tossdk.WithRegion(region),
tossdk.WithBucket(bucket),
)
if err != nil {
return nil, err
@@ -5,10 +5,9 @@ import (
"fmt"
"log/slog"
"github.com/volcengine/ve-tos-golang-sdk/v2/tos"
"github.com/certimate-go/certimate/pkg/core"
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/volcengine-certcenter"
tossdk "github.com/certimate-go/certimate/pkg/sdk3rd/volcengine/tos"
)
type (
@@ -34,7 +33,7 @@ type DeployerConfig struct {
type Deployer struct {
config *DeployerConfig
logger *slog.Logger
sdkClient *tos.ClientV2
sdkClient *tossdk.Client
sdkCertmgr core.Certmgr
}
@@ -45,7 +44,7 @@ func NewDeployer(config *DeployerConfig) (*Deployer, error) {
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
}
client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region)
client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey, config.Region, config.Bucket)
if err != nil {
return nil, fmt.Errorf("could not create client: %w", err)
}
@@ -96,15 +95,14 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
// 设置自定义域名
// REF: https://www.volcengine.com/docs/6349/764779
putBucketCustomDomainReq := &tos.PutBucketCustomDomainInput{
Bucket: d.config.Bucket,
Rule: tos.CustomDomainRule{
putBucketCustomDomainReq := &tossdk.PutBucketCustomDomainRequest{
CustomDomainRule: &tossdk.PutBucketCustomDomainRequestCustomDomainRule{
Domain: d.config.Domain,
CertID: upres.CertId,
CertId: upres.CertId,
},
}
putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomain(ctx, putBucketCustomDomainReq)
d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp))
putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomainWithContext(ctx, putBucketCustomDomainReq)
d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.String("params.bucket", d.config.Bucket), slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'tos.PutBucketCustomDomain': %w", err)
}
@@ -112,13 +110,11 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep
return &DeployResult{}, nil
}
func createSDKClient(accessKeyId, secretAccessKey, region string) (*tos.ClientV2, error) {
endpoint := fmt.Sprintf("tos-%s.volces.com", region)
client, err := tos.NewClientV2(
endpoint,
tos.WithRegion(region),
tos.WithCredentials(tos.NewStaticCredentials(accessKeyId, secretAccessKey)),
func createSDKClient(accessKeyId, secretAccessKey, region, bucket string) (*tossdk.Client, error) {
client, err := tossdk.NewClient("",
tossdk.WithAkSk(accessKeyId, secretAccessKey),
tossdk.WithRegion(region),
tossdk.WithBucket(bucket),
)
if err != nil {
return nil, err
+3 -3
View File
@@ -8,6 +8,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"hash"
"io"
"net/http"
"net/url"
@@ -73,14 +74,13 @@ func NewClient(baseUrl string, optFns ...OptionsFunc) (*Client, error) {
payloadHash := sha256.Sum256([]byte(payloadStr))
payloadHashHex := hex.EncodeToString(payloadHash[:])
h := hmac.New(sha256.New, []byte(opts.SecretAccessKey))
var h hash.Hash
h = hmac.New(sha256.New, []byte(opts.SecretAccessKey))
h.Write([]byte(eopDate))
kTime := h.Sum(nil)
h = hmac.New(sha256.New, kTime)
h.Write([]byte(opts.AccessKeyId))
kAk := h.Sum(nil)
h = hmac.New(sha256.New, kAk)
h.Write([]byte(now.Format("20060102")))
kDate := h.Sum(nil)
+1
View File
@@ -154,6 +154,7 @@ func (c *Client) newRequest(method string, path string, params any) (*resty.Requ
payloadStr := ""
contentType := ""
if params != nil {
// 目前仅支持 XML 请求体,仅适用于非 S3 兼容接口
payloadb, err := xml.Marshal(params)
if err != nil {
return nil, err
-1
View File
@@ -36,7 +36,6 @@ func NewClient(optFns ...OptionsFunc) (*Client, error) {
SetBaseURL("http://api.routewize.com").
SetHeader("Accept", "application/json").
SetHeader("Content-Type", "application/json").
SetHeader("Host", "api.routewize.com").
SetHeader("User-Agent", app.AppUserAgent).
SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
// 签名机制:
@@ -0,0 +1,40 @@
package tos
import (
"context"
"net/http"
)
type PutBucketCustomDomainRequest struct {
CustomDomainRule *PutBucketCustomDomainRequestCustomDomainRule `json:",omitempty"`
}
type PutBucketCustomDomainRequestCustomDomainRule struct {
CertId string `json:",omitempty"`
Domain string `json:",omitempty"`
Protocol string `json:",omitempty"`
}
type PutBucketCustomDomainResponse struct {
sdkResponseBase
}
func (c *Client) PutBucketCustomDomain(req *PutBucketCustomDomainRequest) (*PutBucketCustomDomainResponse, error) {
return c.PutBucketCustomDomainWithContext(context.Background(), req)
}
func (c *Client) PutBucketCustomDomainWithContext(ctx context.Context, req *PutBucketCustomDomainRequest) (*PutBucketCustomDomainResponse, error) {
httpreq, err := c.newRequest(http.MethodPut, "/?customdomain", req)
if err != nil {
return nil, err
} else {
httpreq.SetContext(ctx)
}
result := &PutBucketCustomDomainResponse{}
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
return result, err
}
return result, nil
}
+258
View File
@@ -0,0 +1,258 @@
package tos
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"hash"
"net/http"
"net/url"
"sort"
"strings"
"time"
"github.com/go-resty/resty/v2"
"github.com/certimate-go/certimate/internal/app"
)
type Client struct {
rc *resty.Client
}
func NewClient(endpoint string, optFns ...OptionsFunc) (*Client, error) {
opts := &Options{}
for _, fn := range optFns {
fn(opts)
}
if opts.Region == "" {
return nil, fmt.Errorf("sdkerr: unset region")
}
if opts.AccessKeyId == "" {
return nil, fmt.Errorf("sdkerr: unset accessKeyId")
}
if opts.SecretAccessKey == "" {
return nil, fmt.Errorf("sdkerr: unset secretAccessKey")
}
if endpoint == "" {
if opts.Region == "" {
endpoint = fmt.Sprintf("https://tos-%s.volces.com", url.PathEscape(opts.Region))
} else {
endpoint = fmt.Sprintf("https://%s.tos-%s.volces.com", url.PathEscape(opts.Bucket), url.PathEscape(opts.Region))
}
} else {
if baseUrl, err := url.Parse(endpoint); err != nil {
return nil, fmt.Errorf("sdkerr: invalid endpoint: %w", err)
} else if baseUrl.Scheme == "" {
endpoint = "https://" + endpoint
}
}
restyClient := resty.New().
SetBaseURL(endpoint).
SetHeader("User-Agent", app.AppUserAgent).
SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
// API 签名机制:
// https://www.volcengine.com/docs/6349/74839
// https://docs.byteplus.com/en/docs/tos/reference-signature-mechanism_1
method := strings.ToUpper(req.Method)
nowUtc := time.Now().UTC()
headerDateStr := nowUtc.Format(http.TimeFormat)
requestDateStr := nowUtc.Format("20060102T150405Z")
credentialDateStr := nowUtc.Format("20060102")
canonicalUrl := req.URL.Path
if canonicalUrl == "" {
canonicalUrl = "/"
}
canonicalQueryStr := ""
if len(req.URL.Query()) > 0 {
query := req.URL.Query()
keys := make([]string, 0, len(query))
for key := range query {
keys = append(keys, key)
}
sort.Strings(keys)
for i, key := range keys {
if i > 0 {
canonicalQueryStr += "&"
}
value := query.Get(key)
canonicalQueryStr += fmt.Sprintf("%s=%s", url.QueryEscape(key), url.QueryEscape(value))
}
}
canonicalHeaders := ""
signedHeaders := ""
if len(req.Header) > 0 || req.Host != "" {
if req.Header.Get("Host") == "" {
req.Header.Set("Host", req.Host)
}
if req.Header.Get("X-TOS-Date") == "" {
req.Header.Set("X-TOS-Date", requestDateStr)
}
keys := make([]string, 0, len(req.Header))
for key := range req.Header {
key = strings.ToLower(key)
if strings.HasPrefix(key, "x-tos-") || key == "host" {
keys = append(keys, key)
}
if key == "content-type" && req.Header.Get("X-TOS-Content-SHA256") != "" {
keys = append(keys, key)
}
}
sort.Strings(keys)
for i, key := range keys {
if i > 0 {
canonicalHeaders += "\n"
signedHeaders += ";"
}
value := strings.TrimSpace(req.Header.Get(key))
canonicalHeaders += fmt.Sprintf("%s:%s", key, value)
signedHeaders += key
}
canonicalHeaders += "\n"
}
payloadSha256Str := req.Header.Get("X-TOS-Content-SHA256")
if payloadSha256Str == "" {
payloadSha256 := sha256.Sum256([]byte{})
payloadSha256Str = strings.ToLower(hex.EncodeToString(payloadSha256[:]))
}
canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", method, canonicalUrl, canonicalQueryStr, canonicalHeaders, signedHeaders, payloadSha256Str)
canonicalRequestHash := sha256.Sum256([]byte(canonicalRequest))
canonicalRequestHashHex := strings.ToLower(hex.EncodeToString(canonicalRequestHash[:]))
const signAlgorithmHeader = "TOS4-HMAC-SHA256"
credentialScope := fmt.Sprintf("%s/%s/tos/request", credentialDateStr, opts.Region)
stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s", signAlgorithmHeader, requestDateStr, credentialScope, canonicalRequestHashHex)
var h hash.Hash
h = hmac.New(sha256.New, []byte(opts.SecretAccessKey))
h.Write([]byte(credentialDateStr))
kDate := h.Sum(nil)
h = hmac.New(sha256.New, kDate)
h.Write([]byte(opts.Region))
kRegion := h.Sum(nil)
h = hmac.New(sha256.New, kRegion)
h.Write([]byte("tos"))
kService := h.Sum(nil)
h = hmac.New(sha256.New, kService)
h.Write([]byte("request"))
kSigning := h.Sum(nil)
h = hmac.New(sha256.New, kSigning)
h.Write([]byte(stringToSign))
signature := strings.ToLower(hex.EncodeToString(h.Sum(nil)))
req.Header.Set("Authorization", fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", signAlgorithmHeader, opts.AccessKeyId, credentialScope, signedHeaders, signature))
req.Header.Set("Date", headerDateStr)
return nil
})
return &Client{rc: restyClient}, nil
}
func (c *Client) SetTimeout(timeout time.Duration) *Client {
c.rc.SetTimeout(timeout)
return c
}
func (c *Client) newRequest(method string, path string, params any) (*resty.Request, error) {
if method == "" {
return nil, fmt.Errorf("sdkerr: unset method")
}
if path == "" {
return nil, fmt.Errorf("sdkerr: unset path")
}
requestUrl, err := url.Parse(path)
if err != nil {
return nil, fmt.Errorf("sdkerr: invalid path: %w", err)
} else if requestUrl.IsAbs() {
return nil, fmt.Errorf("sdkerr: path should be relative")
}
payloadStr := ""
contentType := ""
if params != nil {
// 目前仅支持 JSON 请求体,仅适用于非 S3 兼容接口
payloadb, err := json.Marshal(params)
if err != nil {
return nil, err
}
payloadStr = string(payloadb)
contentType = "application/json"
}
payloadMd5 := md5.Sum([]byte(payloadStr))
payloadMd5Encoded := base64.StdEncoding.EncodeToString(payloadMd5[:])
req := c.rc.R()
req.Method = method
req.URL = requestUrl.Path
req.QueryParam = requestUrl.Query()
req.SetBody(payloadStr)
req.SetHeader("Content-MD5", payloadMd5Encoded)
req.SetHeader("Content-Type", contentType)
return req, nil
}
func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) {
if req == nil {
return nil, fmt.Errorf("sdkerr: nil request")
}
// WARN:
// PLEASE DO NOT USE `req.SetBody` HERE! USE `newRequest` INSTEAD.
// PLEASE DO NOT USE `req.SetResult` or `req.SetError` HERE! USE `doRequestWithResult` INSTEAD.
resp, err := req.Send()
if err != nil {
return resp, fmt.Errorf("sdkerr: failed to send request: %w", err)
} else if resp.IsError() {
return resp, fmt.Errorf("sdkerr: unexpected status code: %d (resp: %s)", resp.StatusCode(), resp.String())
}
return resp, nil
}
func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) {
if req == nil {
return nil, fmt.Errorf("sdkerr: nil request")
}
resp, err := c.doRequest(req)
if err != nil {
if resp != nil {
json.Unmarshal(resp.Body(), &res)
}
return resp, err
}
if len(resp.Body()) != 0 {
if err := json.Unmarshal(resp.Body(), &res); err != nil {
return resp, fmt.Errorf("sdkerr: failed to unmarshal response: %w (resp: %s)", err, resp.String())
}
}
return resp, nil
}
+29
View File
@@ -0,0 +1,29 @@
package tos
type Options struct {
AccessKeyId string
SecretAccessKey string
Region string
Bucket string
}
type OptionsFunc func(*Options)
func WithAkSk(ak, sk string) OptionsFunc {
return func(o *Options) {
o.AccessKeyId = ak
o.SecretAccessKey = sk
}
}
func WithRegion(region string) OptionsFunc {
return func(o *Options) {
o.Region = region
}
}
func WithBucket(bucket string) OptionsFunc {
return func(o *Options) {
o.Bucket = bucket
}
}
+7
View File
@@ -0,0 +1,7 @@
package tos
type sdkResponse interface{}
type sdkResponseBase struct{}
var _ sdkResponse = (*sdkResponseBase)(nil)
+4 -5
View File
@@ -40,7 +40,6 @@ func NewClient(optFns ...OptionsFunc) (*Client, error) {
SetBaseURL("https://open.chinanetcenter.com").
SetHeader("Accept", "application/json").
SetHeader("Content-Type", "application/json").
SetHeader("Host", "open.chinanetcenter.com").
SetHeader("User-Agent", app.AppUserAgent).
SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
// API 签名机制:
@@ -67,7 +66,7 @@ func NewClient(optFns ...OptionsFunc) (*Client, error) {
canonicalHeaders := "" +
"content-type:" + strings.TrimSpace(strings.ToLower(req.Header.Get("Content-Type"))) + "\n" +
"host:" + strings.TrimSpace(strings.ToLower(req.Header.Get("Host"))) + "\n"
"host:" + strings.TrimSpace(strings.ToLower(req.Host)) + "\n"
signedHeaders := "content-type;host"
payloadStr := ""
@@ -106,11 +105,11 @@ func NewClient(optFns ...OptionsFunc) (*Client, error) {
h.Write([]byte(stringToSign))
signature := strings.ToLower(hex.EncodeToString(h.Sum(nil)))
req.Header.Set("X-CNC-AccessKey", options.AccessKey)
req.Header.Set("X-CNC-Timestamp", timestampStr)
req.Header.Set("X-CNC-Auth-Method", "AKSK")
req.Header.Set("Authorization", fmt.Sprintf("%s Credential=%s, SignedHeaders=%s, Signature=%s", signAlgorithmHeader, options.AccessKey, signedHeaders, signature))
req.Header.Set("Date", nowUtc.Format(http.TimeFormat))
req.Header.Set("X-CNC-Auth-Method", "AKSK")
req.Header.Set("X-CNC-AccessKey", options.AccessKey)
req.Header.Set("X-CNC-Timestamp", timestampStr)
return nil
})