<p align="center">
<a href="https://cloud.tencent.com/"><img src="https://imgcache.qq.com/qcloud/tcloud_dtc/static/static_source_business/eec00e38-a178-479f-83d4-853a18575ac4.png" height="100" ></a>
</p>
<h1 align="center">Tencent Cloud SDK for Go</h1>

# 目录
1. [简介](#简介)
2. [安装](#获取安装)
3. [快速开始](#快速开始)
4. [相关配置](#相关配置)
5. [功能介绍](#功能介绍)
   - [凭证管理](#凭证管理)
   - [错误处理](#错误处理)
   - [Common Client](#Common-Client)
   - [自定义Header](#自定义-header)
   - [http代理](#http-代理)
   - [请求重试](#请求重试)
   - [空数组和omitempty](#空数组和omitempty)


# 简介

欢迎使用腾讯云开发者工具套件（SDK），此 SDK 是云 API 3.0 平台的配套开发工具。

# 获取安装

## 依赖环境

1. Go 1.9 版本及以上（如使用 go mod 需要 Go 1.14）。
2. 部分产品需要在腾讯云控制台开通后，才能正常调用此产品的接口。
3. 在腾讯云控制台 [访问管理](https://console.cloud.tencent.com/cam/capi) 页面获取密钥 SecretID 和 SecretKey，请务必妥善保管，或者使用更安全的临时安全凭证。


## 通过go get安装（推荐）

推荐使用腾讯云镜像加速下载：

1. Linux 或 MacOS:

    ```bash
    export GOPROXY=https://mirrors.tencent.com/go/
    ```

2. Windows:

    ```cmd
    set GOPROXY=https://mirrors.tencent.com/go/
    ```

## 按需安装（推荐）

注意：此安装方式仅支持使用 **Go Modules** 模式进行依赖管理，即环境变量 `GO111MODULE=auto`或者`GO111MODULE=on`, 并且在您的项目中执行了 `go mod init xxx`.

如果您使用 GOPATH, 请参考下节： 全部安装

v1.0.170后可以按照产品下载，您只需下载基础包和对应的产品包(如cvm)即可，不需要下载全部的产品，从而加快您构建镜像或者编译的速度：

1. 安装公共基础包：

    ```bash
    go get -v -u github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common
    ```

2. 安装对应的产品包(如cvm):

    ```bash
    go get -v -u github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm
    ```

注意：为了支持 go mod，SDK 版本号从 v3.x 降到了 v1.x。并于2021.05.10移除了所有`v3.0.*`和`3.0.*`的tag，如需追溯以前的tag，请参考项目根目录下的 `commit2tag` 文件。

## 通过源码安装

前往代码托管地址 [Github](https://github.com/tencentcloud/tencentcloud-sdk-go) 或者 [Gitee](https://gitee.com/tencentcloud/tencentcloud-sdk-go) 下载最新代码，解压后安装到 $GOPATH/src/github.com/tencentcloud 目录下。

# 快速开始

每个接口都有一个对应的 Request 结构和一个 Response 结构。例如云服务器的查询实例列表接口 DescribeInstances 有对应的请求结构体 DescribeInstancesRequest 和返回结构体 DescribeInstancesResponse 。

下面以云服务器查询实例列表接口为例，介绍 SDK 的基础用法。

## 简化版

```go
package main

import (
	"fmt"
    "os"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions"
	cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)

func main() {
    // 硬编码密钥到代码中有可能随代码泄露而暴露，有安全隐患，并不推荐。
    // 为了保护密钥安全，建议将密钥设置在环境变量中或者配置文件中，请参考本文凭证管理章节。
    // credential := common.NewCredential("SecretId", "SecretKey")
    credential := common.NewCredential(
        os.Getenv("TENCENTCLOUD_SECRET_ID"),
        os.Getenv("TENCENTCLOUD_SECRET_KEY"),
    )
	client, _ := cvm.NewClient(credential, regions.Guangzhou, profile.NewClientProfile())

	request := cvm.NewDescribeInstancesRequest()
	response, err := client.DescribeInstances(request)

	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		fmt.Printf("An API error has returned: %s", err)
		return
	}
	if err != nil {
		panic(err)
	}
	fmt.Printf("%s\n", response.ToJsonString())
}
```

## 详细版

出于演示的目的，有一些非必要的代码，例如对默认配置的修改，以尽量展示 SDK 的功能。在实际编写代码使用 SDK 的时候，建议尽量使用默认配置，酌情修改。

```go
package main

import (
	"fmt"
    "os"

	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions"
	cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)

func main() {
        // 必要步骤：
        // 实例化一个认证对象，入参需要传入腾讯云账户密钥对 SecretId，SecretKey。
        // 硬编码密钥到代码中有可能随代码泄露而暴露，有安全隐患，并不推荐。
        // 为了保护密钥安全，建议将密钥设置在环境变量中或者配置文件中，请参考本文凭证管理章节。
        // credential := common.NewCredential("SecretId", "SecretKey")
        credential := common.NewCredential(
            os.Getenv("TENCENTCLOUD_SECRET_ID"),
            os.Getenv("TENCENTCLOUD_SECRET_KEY"),
        )

        // 非必要步骤
        // 实例化一个客户端配置对象，可以指定超时时间等配置
        cpf := profile.NewClientProfile()
        // SDK默认使用POST方法。
        // 如果你一定要使用GET方法，可以在这里设置。GET方法无法处理一些较大的请求。
        // 如非必要请不要修改默认设置。
        cpf.HttpProfile.ReqMethod = "POST"
        // SDK有默认的超时时间，如非必要请不要修改默认设置。
        // 如有需要请在代码中查阅以获取最新的默认值。
        cpf.HttpProfile.ReqTimeout = 30
        // SDK会自动指定域名。通常是不需要特地指定域名的，但是如果你访问的是金融区的服务，
        // 则必须手动指定域名，例如云服务器的上海金融区域名： cvm.ap-shanghai-fsi.tencentcloudapi.com
        cpf.HttpProfile.Endpoint = "cvm.tencentcloudapi.com"
        // SDK默认用TC3-HMAC-SHA256进行签名，它更安全但是会轻微降低性能。
        // 如非必要请不要修改默认设置。
        cpf.SignMethod = "TC3-HMAC-SHA256"
        // SDK 默认用 zh-CN 调用返回中文。此外还可以设置 en-US 返回全英文。
        // 但大部分产品或接口并不支持全英文的返回。
        // 如非必要请不要修改默认设置。
        cpf.Language = "en-US"
        //打印日志，默认是false
        // cpf.Debug = true


        // 实例化要请求产品(以cvm为例)的client对象
        // 第二个参数是地域信息，可以直接填写字符串ap-guangzhou，或者引用预设的常量
        client, _ := cvm.NewClient(credential, regions.Guangzhou, cpf)
        // 实例化一个请求对象，根据调用的接口和实际情况，可以进一步设置请求参数
        // 你可以直接查询SDK源码确定DescribeInstancesRequest有哪些属性可以设置，
        // 属性可能是基本类型，也可能引用了另一个数据结构。
        // 推荐使用IDE进行开发，可以方便的跳转查阅各个接口和数据结构的文档说明。
        request := cvm.NewDescribeInstancesRequest()

        // 基本类型的设置。
        // 此接口允许设置返回的实例数量。此处指定为只返回一个。
        // SDK采用的是指针风格指定参数，即使对于基本类型你也需要用指针来对参数赋值。
        // SDK提供对基本类型的指针引用封装函数
        request.Limit = common.Int64Ptr(1)

        // 数组类型的设置。
        // 此接口允许指定实例 ID 进行过滤，但是由于和接下来要演示的 Filter 参数冲突，先注释掉。
        // request.InstanceIds = common.StringPtrs([]string{"ins-r8hr2upy"})

        // 复杂对象的设置。
        // 在这个接口中，Filters是数组，数组的元素是复杂对象Filter，Filter的成员Values是string数组。
        request.Filters = []*cvm.Filter{
            &cvm.Filter{
                Name: common.StringPtr("zone"),
                Values: common.StringPtrs([]string{"ap-guangzhou-1"}),
            },
        }

        // 通过client对象调用想要访问的接口，需要传入请求对象
        response, err := client.DescribeInstances(request)
        // 处理异常
        if _, ok := err.(*errors.TencentCloudSDKError); ok {
            fmt.Printf("An API error has returned: %s", err)
            return
        }
        // 非SDK异常，直接失败。实际代码中可以加入其他的处理。
        if err != nil {
            panic(err)
        }
        // 打印返回的json字符串
        fmt.Printf("%s\n", response.ToJsonString())
}
```

更多示例参见 [examples](https://github.com/TencentCloud/tencentcloud-sdk-go/tree/master/examples) 目录。对于复杂接口的 Request 初始化例子，可以参考 [例一](examples/cvm/v20170312/run_instances.go) 。对于使用json字符串初始化 Request 的例子，可以参考 [例二](examples/cvm/v20170312/describe_instances.go) 。

# 相关配置

**如无特殊需要，建议您使用默认配置。**

在创建客户端前，如有需要，您可以通过修改`profile.ClientProfile`中字段的值进行一些配置。

```go
// 非必要步骤
// 实例化一个客户端配置对象，可以指定超时时间等配置
cpf := profile.NewClientProfile()
```

具体的配置项说明如下：

## 请求方式

SDK默认使用POST方法。 如果你一定要使用GET方法，可以在这里设置。**GET方法无法处理一些较大的请求**。

```go
cpf.HttpProfile.ReqMethod = "POST"
```

## 超时时间

SDK有默认的超时时间，如非必要请不要修改默认设置。
如有需要请在代码中查阅以获取最新的默认值。  
单位：秒

```go
cpf.HttpProfile.ReqTimeout = 30
```

## 指定域名

SDK会自动指定域名。通常是不需要特地指定域名的，但是如果你访问的是金融区的服务，
则必须手动指定域名，例如云服务器的上海金融区域名： cvm.ap-shanghai-fsi.tencentcloudapi.com

```go
cpf.HttpProfile.Endpoint = "cvm.tencentcloudapi.com"
```

## 签名方式

SDK默认用 `TC3-HMAC-SHA256` 进行签名，它更安全但是会轻微降低性能。

```go
cpf.SignMethod = "HmacSHA1"
```

## DEBUG模式

DEBUG模式会打印更详细的日志，当您需要进行详细的排查错误时可以开启。  
默认为 `false`

```go
cpf.Debug = true
```

## 禁用长连接(Keep-alive)

SDK 的每一个 client 默认使用长连接模式，即请求的头部 Connection 字段的值为 keep-alive.

如果您需要使用短连接，可以按照以下方式进行设置：

```go
...
    client, _ := cvm.NewClient(credential, regions.Guangzhou, cpf)
    tp := &http.Transport{
        DisableKeepAlives: true,
    }
    client.WithHttpTransport(tp)
...
```

则此 client 发出的每个请求头部的 Connection 字段的值为 close

## 地域容灾

从 `v1.0.227`开始，腾讯云 GO SDK 支持地域容灾功能：

当请求满足以下条件时：

1. 失败次数 >= 5 次
2. 失败率 >= 75%

SDK 会自动将您请求的地域设置为备选地域。

相关设置如下：

```golang
    // 开启
    cpf.DisableRegionBreaker = false
    // 设置备用请求地址，不需要指定服务，SDK 会自动在头部加上服务名(如cvm)
    // 例如，设置为 ap-guangzhou.tencentcloudapi.com，则最终的请求为 cvm.ap-guangzhou.tencentcloudapi.com
    cpf.BackupEndpoint = "ap-guangzhou.tencentcloudapi.com"
```

此功能仅支持单个客户端的同步请求。

## 代理

如果是有代理的环境下，需要设置系统环境变量 `https_proxy` ，否则可能无法正常调用，抛出连接超时的异常。或者自定义 Transport 指定代理，通过 client.WithHttpTransport 覆盖默认配置。

## 开启 DNS 缓存

当前 GO SDK 总是会去请求 DNS 服务器，而没有使用到 nscd 的缓存，可以通过导出环境变量`GODEBUG=netdns=cgo`，或者`go build`编译时指定参数`-tags 'netcgo'`控制读取 nscd 缓存。

## 忽略服务器证书校验

虽然使用 SDK 调用公有云服务时，必须校验服务器证书，以识破他人伪装的服务器，确保请求的安全。
但是某些极端情况下，例如测试时，你可能会需要忽略自签名的服务器证书。
以下是其中一种可能的方法：

```golang
import "crypto/tls"
...
    client, _ := cvm.NewClient(credential, regions.Guangzhou, cpf)
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    client.WithHttpTransport(tr)
...
```

**再次强调，除非你知道自己在做什么，并明白由此带来的风险，否则不要尝试关闭服务器证书校验。**

# 功能介绍

## 凭证管理

从版本 `v1.0.217` 开始，腾讯云 GO SDK 支持以下几种方式进行凭证管理：

1. 环境变量

    默认读取环境变量 `TENCENTCLOUD_SECRET_ID` 和 `TENCENTCLOUD_SECRET_KEY` 获取 secretId 和 secretKey.
    相关代码如下：

    ```go
    provider := common.DefaultEnvProvider()
    credential, err := provider.GetCredential()
    ```

2. 配置文件

    配置文件路径为：
   1. 环境变量 `TENCENTCLOUD_CREDENTIALS_FILE` 所指定的路径
   2. Linux or MacOS: `~/.tencentcloud/credentials`
   3. Windows: `c:\Users\NAME\.tencentcloud\credentials`

    配置文件格式如下：

    ```ini
    [default]
    secret_id = xxxxx
    secret_key = xxxxx
    ```

    相关代码如下：

    ```go
    provider := common.DefaultProfileProvider()
    credential, err := provider.GetCredential()
    ```

3. 角色扮演

    有关角色扮演的相关概念请参阅：[腾讯云角色概述](https://cloud.tencent.com/document/product/598/19420)

    要使用此种方式，您必须在腾讯云访问管理控制台上创建了一个角色，具体创建过程请参阅：[腾讯云角色创建](https://cloud.tencent.com/document/product/598/19381)

    在您拥有角色后，可以通过如下方式获取凭证：

    ```go
    provider := common.DefaultRoleArnProvider(secretId, secretKey, roleArn)
    credential, err := provider.GetCredential()
    ```

4. 实例角色

    有关实例角色的相关概念请参阅：[腾讯云实例角色](https://cloud.tencent.com/document/product/213/47668)

    在您为实例绑定角色后，您可以在实例中访问相关元数据接口获取临时凭证。相关代码如下：

    ```go
    provider := common.DefaultCvmRoleProvider()
    credential, err := provider.GetCredential()
    ```
   
5. TKE OIDC凭证

   有关 TKE OIDC 凭证的相关示例请参阅：[Pod 使用 CAM 对数据库身份验证](https://cloud.tencent.com/document/product/457/81989)

   示例代码请参考 examples/ssm/v20190923/get_secret_value.go
   ```go
   provider, err := common.DefaultTkeOIDCRoleArnProvider()
   credential, err := provider.GetCredential()
   ```

6. 凭证提供链

    腾讯云 GO SDK 提供了 凭证提供链，它会默认以 `环境变量->配置文件->实例角色` 的顺序尝试获取凭证，并返回第一个获取到的凭证。相关代码如下：

    ```go
    provider := common.DefaultProviderChain()
    credential, err := provider.GetCredential()
    ```

    您也可以自定义自己的凭证提供链，从而改变其调用顺序：

    ```go
    provider1 := common.DefaultCvmRoleProvider()
    provider2 := common.DefaultEnvProvider()
    customProviderChain := []common.Provider{provider1, provider2}
    provider := common.NewProviderChain(customProviderChain)
    credential, err := provider.GetCredential()
    ```

    更详细的使用方式请参考示例：[使用ProviderChain](https://github.com/TencentCloud/tencentcloud-sdk-go/blob/master/testing/integration/provider_chain_test.go)

## 错误处理

从 `v1.0.181` 开始，腾讯云 GO SDK 会将各个产品的返回的错误码定义为常量，您可以直接调用处理，无需手动定义。如果您使用 IDE (如 Goland )进行开发，可以使用他们的代码提示功能直接选择。例如：

```go
...//Your other go code

// Handling errors
response, err := client.DescribeInstances(request)
if terr, ok := err.(*errors.TencentCloudSDKError); ok {
    code := terr.GetCode()
    if code == cvm.FAILEDOPERATION_ILLEGALTAGKEY{
        fmt.Printf("Handling error: FailedOperation.IllegalTagKey,%s", err)
    }else if code == cvm.UNAUTHORIZEDOPERATION{
        fmt.Printf("Handling error: UnauthorizedOperation,%s", err)
    }else{
        fmt.Printf("An API error has returned: %s", err)
    }
    return
}
...
```

同时，各个接口函数的注释部分也列出了此接口可能会返回的错误码，方便您进行处理：

```go
// DescribeInstances
// 本接口 (DescribeInstances) 用于查询一个或多个实例的详细信息。
//
// 
//
// * 可以根据实例`ID`、实例名称或者实例计费模式等信息来查询实例的详细信息。过滤信息详细请见过滤器`Filter`。
//
// * 如果参数为空，返回当前用户一定数量（`Limit`所指定的数量，默认为20）的实例。
//
// * 支持查询实例的最新操作（LatestOperation）以及最新操作状态(LatestOperationState)。
//
// 可能返回的错误码:
//  FAILEDOPERATION_ILLEGALTAGKEY = "FailedOperation.IllegalTagKey"
//  FAILEDOPERATION_ILLEGALTAGVALUE = "FailedOperation.IllegalTagValue"
//  FAILEDOPERATION_TAGKEYRESERVED = "FailedOperation.TagKeyReserved"
//  INTERNALSERVERERROR = "InternalServerError"
//  INVALIDFILTER = "InvalidFilter"
//  INVALIDFILTERVALUE_LIMITEXCEEDED = "InvalidFilterValue.LimitExceeded"
//  INVALIDHOSTID_MALFORMED = "InvalidHostId.Malformed"
//  INVALIDINSTANCEID_MALFORMED = "InvalidInstanceId.Malformed"
//  INVALIDPARAMETER = "InvalidParameter"
//  INVALIDPARAMETERVALUE = "InvalidParameterValue"
//  INVALIDPARAMETERVALUE_IPADDRESSMALFORMED = "InvalidParameterValue.IPAddressMalformed"
//  INVALIDPARAMETERVALUE_INVALIDIPFORMAT = "InvalidParameterValue.InvalidIpFormat"
//  INVALIDPARAMETERVALUE_INVALIDVAGUENAME = "InvalidParameterValue.InvalidVagueName"
//  INVALIDPARAMETERVALUE_LIMITEXCEEDED = "InvalidParameterValue.LimitExceeded"
//  INVALIDPARAMETERVALUE_SUBNETIDMALFORMED = "InvalidParameterValue.SubnetIdMalformed"
//  INVALIDPARAMETERVALUE_TAGKEYNOTFOUND = "InvalidParameterValue.TagKeyNotFound"
//  INVALIDPARAMETERVALUE_VPCIDMALFORMED = "InvalidParameterValue.VpcIdMalformed"
//  INVALIDSECURITYGROUPID_NOTFOUND = "InvalidSecurityGroupId.NotFound"
//  INVALIDSGID_MALFORMED = "InvalidSgId.Malformed"
//  INVALIDZONE_MISMATCHREGION = "InvalidZone.MismatchRegion"
//  RESOURCENOTFOUND_HPCCLUSTER = "ResourceNotFound.HpcCluster"
//  UNAUTHORIZEDOPERATION_INVALIDTOKEN = "UnauthorizedOperation.InvalidToken"
func (c *Client) DescribeInstances(request *DescribeInstancesRequest) (response *DescribeInstancesResponse, err error){
    ...
}
```

## Common Client

从 `v1.0.189`开始，腾讯云 GO SDK 支持使用 `泛用型的API调用方式(Common Client)` 进行请求。您只需安装 `common` 包, 即可向任何产品发起调用。

**注意，您必须明确知道您调用接口的参数内容，否则会调用失败。**

目前仅支持使用 POST 方式发送请求，且签名方法必须使用 签名方法 v3。

详细使用请参阅示例：[使用 Common Client 进行调用](https://github.com/TencentCloud/tencentcloud-sdk-go/blob/master/examples/common/common_client.go)

## 自定义 Header

[RunInstancesRequest示例](examples/cvm/v20170312/run_instances.go)
```go
    request := cvm.NewRunInstancesRequest()
	request.SetHeader(map[string]string{
        "X-TC-TraceId": "ffe0c072-8a5d-4e17-8887-a8a60252abca",
    })
```

[CommonRequest示例](examples/common/common_client.go)

```go
    request := tchttp.NewCommonRequest("cvm", "2017-03-12", "DescribeZones")
    request.SetHeader(map[string]string{
        "X-TC-TraceId": "ffe0c072-8a5d-4e17-8887-a8a60252abca",
    })
```

## http 代理
[DescribeInstances示例](examples/cvm/v20170312/describe_instances.go)
```go
    // with authentication
    clientProfile.HttpProfile.Proxy = "http://username:password@127.0.0.1:1080"
    // without authentication
    clientProfile.HttpProfile.Proxy = "http://127.0.0.1:1080"
```

## 请求重试

### 网络错误重试

当发生临时网络错误或超时时，SDK可以被配置为自动重试。默认不开启。
通过 `ClientProfile` 配置重试次数和重试间隔时间。

> 通过反射检查 `Request` 结构体是否存在 `ClientToken` 字段，存在该字段则认为是幂等请求。
> 幂等请求才会在网络错误时自动重试，非幂等请求会抛出异常，防止请求多次重放造成结果不一致。

```golang
package main

import (
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions"
	cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)

func main() {
	credential := common.NewCredential("secretId", "secretKey")
	prof := profile.NewClientProfile()
	prof.NetworkFailureMaxRetries = 3                               // 定义最大重试次数
	prof.NetworkFailureRetryDuration = profile.ExponentialBackoff   // 定义重试间隔时间
	client, _ := cvm.NewClient(credential, regions.Guangzhou, prof)

	// ...
}
```

更多用法参考[测试文件](https://github.com/TencentCloud/tencentcloud-sdk-go/tree/master/tencentcloud/common/netretry_test.go)

### 限频重试

当发生API限频时，SDK可以被配置为自动重试。默认不开启。
通过 `ClientProfile` 配置重试次数和重试间隔时间。

```golang
package main

import (
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions"
	cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)

func main() {
	// ...

	prof := profile.NewClientProfile()
	prof.RateLimitExceededMaxRetries = 3                               // 定义最大重试次数
	prof.RateLimitExceededRetryDuration = profile.ExponentialBackoff   // 定义重试间隔时间
	client, _ := cvm.NewClient(credential, regions.Guangzhou, prof)

	// ...
}
```

### 幂等标识符

当网络超时重试或限频重试开启时，会自动向请求中注入 `ClientToken` 参数（如果请求存在`ClientToken`字段且为空）。
当用户手动指定 `ClientToken` 时，会跳过注入流程。

> 注入的 `ClientToken` 在 `100000/s` 并发量以下提供全局唯一性。

## 空数组和omitempty
SDK 使用 `omitempty` 标签来序列化你的 request 对象, 因为这样可以避免上报空数组/对象. 

但对有的接口而言, 长度为0的数组 和 nil数组 是有区别的, 如果你希望在请求中携带空数组, 需要使用Common Client 来发送请求.

参考[示例](examples/common/omitempty.go)

# 支持产品列表

参见[产品列表文档](./products.md)
