
# Go
|    样例    | [发送短信示例]、[发送分批短信示例]、[接收状态报告示例]、[接收上行短信示例] |
|---|---|
| **环境要求** | [go1.17.1](https://golang.google.cn/dl/go1.17.1.windows-amd64.msi)，IntelliJ IDEA 2021.1.3安装插件（Go 211.7628.1）                                                                                                                                                  |
   
![](https://support.huaweicloud.com/devg-msgsms/public_sys-resources/notice_3.0-zh-cn.png)
- 发送短信为单模板群发短信示例，发送分批短信为多模板群发短信示例。

- 本文档所述Demo在提供服务的过程中，可能会涉及个人数据的使用，建议您遵从国家的相关法律采取足够的措施，以确保用户的个人数据受到充分的保护。
- 本文档所述Demo仅用于功能演示，不允许客户直接进行商业使用。
- 本文档信息仅供参考，不构成任何要约或承诺。
 
参考[API签名SDK与demo](https://support.huaweicloud.com/devg-apisign/api-sign-sdk-go.html)，点击下载其中的SDK与Demo。将下列代码样例替换demo.go文件内容即可。
由于使用的是go1.17, 请将首层go.mod文件内容修改为:
```
module huaweicloud.com/apig/go/signer
require huaweicloud.com/apig/signer v0.0.0
replace huaweicloud.com/apig/signer v0.0.0 => ./core
go 1.12
```
![](https://support.huaweicloud.com/devg-msgsms/figure/zh-cn_image_0000001613796669.png "点击放大")
 #### 发送短信示例
```
package main
import (
   "bytes"
   "crypto/tls"
   "fmt"
   core "huaweicloud.com/apig/signer"
   "io/ioutil"
   "net/http"
   "net/url"
)
func main() {
   //必填,请参考"开发准备"获取如下数据,替换为实际值
   appInfo := core.Signer{
      // 认证用的appKey和appSecret硬编码到代码中或者明文存储都有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全；
      Key:    "c8RWg3ggEcyd4D3p94bf3Y7x1Ile", //App Key
      Secret: "q4Ii87Bh************80SfD7Al", //App Secret
   }
   apiAddress := "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1" //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI
   sender := "csms12345678"                                    //国内短信签名通道号
   templateId := "8ff55eac1d0b478ab3c06c3c6a492300"               //模板ID
   //条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
   
   signature := "华为云短信测试" //签名名称
   //必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
   receiver := "+86151****6789" //短信接收人号码
   //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
   statusCallBack := ""
   /*
    * 选填,使用无变量模板时请赋空值 string templateParas = "";
    * 单变量模板示例:模板内容为"您的验证码是${1}"时,templateParas可填写为"[\"369751\"]"
    * 双变量模板示例:模板内容为"您有${1}件快递请到${2}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]"
    * 模板中的每个变量都必须赋值，且取值不能为空
    * 查看更多模板规范和变量规范:产品介绍>短信模板须知和短信变量须知
    */
   templateParas := "[\"369751\"]" //模板变量，此处以单变量验证码短信为例，请客户自行生成6位验证码，并定义为字符串类型，以杜绝首位0丢失的问题（例如：002569变成了2569）。
   body := buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature)
   resp, err := post(apiAddress, []byte(body), appInfo)
   if err != nil {
      return
   }
   fmt.Println(resp)
}
/**
 * sender,receiver,templateId不能为空
 */
func buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature string) string {
   param := "from=" + url.QueryEscape(sender) + "&to=" + url.QueryEscape(receiver) + "&templateId=" + url.QueryEscape(templateId)
   if templateParas != "" {
      param += "&templateParas=" + url.QueryEscape(templateParas)
   }
   if statusCallBack != "" {
      param += "&statusCallback=" + url.QueryEscape(statusCallBack)
   }
   if signature != "" {
      param += "&signature=" + url.QueryEscape(signature)
   }
   return param
}
func post(url string, param []byte, appInfo core.Signer) (string, error) {
   if param == nil || appInfo == (core.Signer{}) {
      return "", nil
   }
   // 代码样例为了简便，设置了不进行证书校验，请在商用环境自行开启证书校验。
   tr := &http.Transport{
      TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
   }
   client := &http.Client{Transport: tr}
   req, err := http.NewRequest("POST", url, bytes.NewBuffer(param))
   if err != nil {
      return "", err
   }
   // 对请求增加内容格式，固定头域
   req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
   // 对请求进行HMAC算法签名，并将签名结果设置到Authorization头域。
   appInfo.Sign(req)
   fmt.Println(req.Header)
   // 发送短信请求
   resp, err := client.Do(req)
   if err != nil {
      fmt.Println(err)
   }
   // 获取短信响应
   defer resp.Body.Close()
   body, err := ioutil.ReadAll(resp.Body)
   if err != nil {
      return "", err
   }
   return string(body), nil
}
```
 #### 发送分批短信示例
```
package main
import (
   "bytes"
   "crypto/tls"
   "encoding/json"
   "fmt"
   core "huaweicloud.com/apig/signer"
   "io/ioutil"
   "net/http"
)
func main() {
   //必填,请参考"开发准备"获取如下数据,替换为实际值
   apiAddress := "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendDiffSms/v1" //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI
   // 认证用的appKey和appSecret硬编码到代码中或者明文存储都有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全；
   appKey := "c8RWg3ggEcyd4D3p94bf3Y7x1Ile"                                         //APP_Key
   appSecret := "q4Ii87Bh************80SfD7Al"                                      //APP_Secret
   sender := "csms12345678"                                                         //国内短信签名通道号
   templateId1 := "8ff55eac1d0b478ab3c06c3c6a492300"                                //模板ID1
   templateId2 := "8ff55eac1d0b478ab3c06c3c6a492300"                                //模板ID2
   //条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
   
   signature1 := "华为云短信测试" //签名名称1
   signature2 := "华为云短信测试" //签名名称2
   //必填,全局号码格式(包含国家码),示例:+8615123456789,多个号码之间用英文逗号分隔
   receiver1 := []string{"+86151****6789", "+86152****7890"} //模板1的接收号码
   receiver2 := []string{"+86151****6789", "+86152****7890"} //模板2的接收号码
   //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
   statusCallBack := ""
   /**
    * 选填,使用无变量模板时请赋空值 templateParas := []string{}
    * 单变量模板示例:模板内容为"您的验证码是${1}"时,templateParas可填写为[]string{"369751"}
    * 双变量模板示例:模板内容为"您有${1}件快递请到${2}领取"时,templateParas可填写为[]string{{"3","人民公园正门"}
    * ${DATE}${TIME}变量不允许取值为空,${TXT_20}变量可以使用英文空格或点号替代空值,${NUM_6}变量可以使用0替代空值
    * 查看更多模板规范和变量规范:产品介绍>短信模板须知和短信变量须知
    */
   templateParas1 := []string{"123456"} //模板1变量，此处以单变量验证码短信为例，请客户自行生成6位验证码，并定义为字符串类型，以杜绝首位0丢失的问题（例如：002569变成了2569）。
   templateParas2 := []string{"234567"} //模板2变量，此处以单变量验证码短信为例，请客户自行生成6位验证码，并定义为字符串类型，以杜绝首位0丢失的问题（例如：002569变成了2569）。
   item1 := initDiffSms(receiver1, templateId1, templateParas1, signature1)
   item2 := initDiffSms(receiver2, templateId2, templateParas2, signature2)
   item := []map[string]interface{}{item1, item2}
   body := buildRequestBody(sender, item, statusCallBack)
   appInfo := core.Signer{
      Key:    appKey, //App Key
      Secret: appSecret, //App Secret
   }
   resp, err := post(apiAddress, []byte(body), appInfo)
   if err != nil {
      return
   }
   fmt.Println(resp)
}
func buildRequestBody(sender string, item []map[string]interface{}, statusCallBack string) []byte {
   body := make(map[string]interface{})
   body["smsContent"] = item
   body["from"] = sender
   if statusCallBack != "" {
      body["statusCallback"] = statusCallBack
   }
   res, _ := json.Marshal(body)
   return res
}
func initDiffSms(reveiver []string, templateId string, templateParas []string, signature string) map[string]interface{} {
   diffSms := make(map[string]interface{})
   diffSms["to"] = reveiver
   diffSms["templateId"] = templateId
   if templateParas != nil && len(templateParas) > 0 {
      diffSms["templateParas"] = templateParas
   }
   if signature != "" {
      diffSms["signature"] = signature
   }
   return diffSms
}
func post(url string, param []byte, appInfo core.Signer) (string, error) {
   if param == nil || appInfo == (core.Signer{}) {
      return "", nil
   }
   // 代码样例为了简便，设置了不进行证书校验，请在商用环境自行开启证书校验。
   tr := &http.Transport{
      TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
   }
   client := &http.Client{Transport: tr}
   req, err := http.NewRequest("POST", url, bytes.NewBuffer(param))
   if err != nil {
      return "", err
   }
   // 对请求增加内容格式，固定头域
   req.Header.Add("Content-Type", "application/json")
   // 对请求进行HMAC算法签名，并将签名结果设置到Authorization头域。
   appInfo.Sign(req)
   fmt.Println(req.Header)
   // 发送短信请求
   resp, err := client.Do(req)
   if err != nil {
      fmt.Println(err)
   }
   // 获取短信响应
   defer resp.Body.Close()
   body, err := ioutil.ReadAll(resp.Body)
   if err != nil {
      return "", err
   }
   return string(body), nil
}
```
 #### 接收状态报告
```
package main
import (
    "fmt"
    "net/url"
    "strings"
)
func main() {
    // 短信平台上报状态报告数据样例(urlencode)
    //success_body := "sequence=1&total=1&updateTime=2018-10-31T08%3A43%3A41Z&source=2&smsMsgId=2ea20735-f856-4376-afbf-570bd70a46ee_11840135&status=DELIVRD";
    failed_body := "sequence=1&total=1&updateTime=2018-10-31T08%3A43%3A41Z&source=2&smsMsgId=2ea20735-f856-4376-afbf-570bd70a46ee_11840135&status=E200027";
    //onSmsStatusReport(success_body);
    onSmsStatusReport(failed_body);
}
func onSmsStatusReport(data string) {
    ss, _ := url.QueryUnescape(data)
    params := strings.Split(ss, "&")
    keyValues := make(map[string]string)
    for i := range params {
        temp := strings.Split(params[i],"=")
        keyValues[temp[0]] = temp[1];
    }
    status := keyValues["status"];
    if status == "DELIVRD" {
        fmt.Println("Send sms success. smsMsgId: " + keyValues["smsMsgId"])
    } else {
        fmt.Println("Send sms failed. smsMsgId: " + keyValues["smsMsgId"])
        fmt.Println("Failed status:  " + keyValues["status"])
    }
}
```
 #### 接收上行短信
```
package main
import (
    "fmt"
    "net/url"
    "strings"
)
func main() {
    upData := "from=%2B86151****6789&to=1069***2019&body=***********&smsMsgId=9692b5be-c427-4525-8e73-cf4a6ac5b3f7";
    onSmsUpData(upData);
}
func onSmsUpData(data string) {
    ss, _ := url.QueryUnescape(data)
    params := strings.Split(ss, "&")
    keyValues := make(map[string]string)
    for i := range params {
        temp := strings.Split(params[i],"=")
        keyValues[temp[0]] = temp[1];
    }
    body := keyValues["body"];
    fmt.Println("Sms up data. Body: " + body)
}
```
#### 相关推荐
| 相关文档                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | 相关产品                                                                                                                                                                  |
|:---|:---|
| - 代码样例：[Java](https://support.huaweicloud.com/devg-msgsms/sms_04_0018.html)/[PHP](https://support.huaweicloud.com/devg-msgsms/sms_04_0013.html)/[Python](https://support.huaweicloud.com/devg-msgsms/sms_04_0014.html)/[C#](https://support.huaweicloud.com/devg-msgsms/sms_04_0015.html)/[3.1.5-Node.js](https://support.huaweicloud.com/devg-msgsms/sms_04_0016.html)/  - [发送短信API](https://support.huaweicloud.com/api-msgsms/sms_05_0001.html)  - [发送分批短信API](https://support.huaweicloud.com/api-msgsms/sms_05_0002.html)  - [接收状态报告API](https://support.huaweicloud.com/api-msgsms/sms_05_0003.html)  - [接收上行短信API](https://support.huaweicloud.com/api-msgsms/sms_05_0004.html)  - [调测问题处理](https://support.huaweicloud.com/api-msgsms/sms_05_0050.html)   | [语音通话](https://www.huaweicloud.com/product/voice.html) [隐私保护通话](https://www.huaweicloud.com/product/privatenumber.html) |
   
