
# Go
|    样例    | [发送短信]、[发送分批短信] [接收状态报告]、[接收上行短信] |
|---|---|
| **环境要求** | go1.11及以上版本                                                                                                                                                                                                                                                                                       |
| **引用库**  | [github.com/satori/go.uuid](https://github.com/satori/go.uuid)                                                                                                                                                                                                                                    |
   
![](https://support.huaweicloud.com/devg-msgsms/public_sys-resources/notice_3.0-zh-cn.png)
- 发送短信为单模板群发短信示例，发送分批短信为多模板群发短信示例。

- 本文档所述Demo在提供服务的过程中，可能会涉及个人数据的使用，建议您遵从国家的相关法律采取足够的措施，以确保用户的个人数据受到充分的保护。
- 本文档所述Demo仅用于功能演示，不允许客户直接进行商业使用。
- 本文档信息仅供参考，不构成任何要约或承诺。
 
 #### 发送短信
```
package main
import (
    "bytes"
    "crypto/sha256"
    "crypto/tls"
    "encoding/base64"
    "fmt"
    "github.com/satori/go.uuid"
    "io/ioutil"
    "net/http"
    "net/url"
    "strings"
    "time"
)
//无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值
const WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""
//无需修改,用于格式化鉴权头域,给"Authorization"参数赋值
const AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""
func main()  {
    //必填,请参考"开发准备"获取如下数据,替换为实际值
    apiAddress := "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1" //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI
    // 认证用的appKey和appSecret硬编码到代码中或者明文存储都有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全；
    appKey := "c8RWg3ggEcyd4D3p94bf3Y7x1Ile" //APP_Key
    appSecret := "q4Ii87Bh************80SfD7Al" //APP_Secret
    sender := "csms12345678" //国内短信签名通道号
    templateId := "8ff55eac1d0b478ab3c06c3c6a492300" //模板ID
    //条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
    
    signature := "华为云短信测试" //签名名称
    //必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
    receiver := "+86151****6789,+86152****7890" //短信接收人号码
    //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
    statusCallBack := ""
    /*
     * 选填,使用无变量模板时请赋空值 string templateParas = "";
     * 单变量模板示例:模板内容为"您的验证码是${1}"时,templateParas可填写为"[\"369751\"]"
     * 双变量模板示例:模板内容为"您有${1}件快递请到${2}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]"
     * 模板中的每个变量都必须赋值，且取值不能为空
     * 查看更多模板规范和变量规范:产品介绍>短信模板须知和短信变量须知
     */
    templateParas := "[\"369751\"]" //模板变量，此处以单变量验证码短信为例，请客户自行生成6位验证码，并定义为字符串类型，以杜绝首位0丢失的问题（例如：002569变成了2569）。
    body := buildRequestBody(sender,receiver,templateId,templateParas,statusCallBack,signature)
    headers := make(map[string]string)
    headers["Content-Type"] = "application/x-www-form-urlencoded"
    headers["Authorization"] = AUTH_HEADER_VALUE;
    headers["X-WSSE"] = buildWsseHeader(appKey, appSecret);
    resp, err := post(apiAddress, []byte(body),headers)
    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, headers map[string]string)(string,error) {
    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
    }
    for key, header := range headers {
        req.Header.Set(key, header)
    }
    resp, err := client.Do(req)
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }
    return string(body), nil;
}
func buildWsseHeader(appKey,appSecret string)string {
    var cTime = time.Now().Format("2006-01-02T15:04:05Z")
    var nonce = uuid.NewV4().String()
    nonce = strings.ReplaceAll(nonce,"-","")
    h := sha256.New()
    h.Write([]byte(nonce + cTime + appSecret))
    passwordDigestBase64Str := base64.StdEncoding.EncodeToString(h.Sum(nil))
    return fmt.Sprintf(WSSE_HEADER_FORMAT,appKey,passwordDigestBase64Str,nonce, cTime);
}
```
 #### 发送分批短信
```
package main
import (
    "bytes"
    "crypto/sha256"
    "crypto/tls"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "github.com/satori/go.uuid"
    "io/ioutil"
    "net/http"
    "strings"
    "time"
)
//无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值
const WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""
//无需修改,用于格式化鉴权头域,给"Authorization"参数赋值
const AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""
func main()  {
//必填,请参考"开发准备"获取如下数据,替换为实际值
    url := "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)
    headers := make(map[string]string)
    headers["Content-Type"] = "application/json;charset=utf-8"
    headers["Authorization"] = AUTH_HEADER_VALUE;
    headers["X-WSSE"] = buildWsseHeader(appKey, appSecret);
    resp, err := post(url,body,headers)
    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, headers map[string]string)(string,error) {
    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
    }
    for key, header := range headers {
        req.Header.Set(key, header)
    }
    resp, err := client.Do(req)
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }
    return string(body), nil;
}
func buildWsseHeader(appKey,appSecret string)string {
    var cTime = time.Now().Format("2006-01-02T15:04:05Z")
    var nonce = uuid.NewV4().String()
    nonce = strings.ReplaceAll(nonce,"-","")
    h := sha256.New()
    h.Write([]byte(nonce + cTime + appSecret))
    passwordDigestBase64Str := base64.StdEncoding.EncodeToString(h.Sum(nil))
    return fmt.Sprintf(WSSE_HEADER_FORMAT,appKey,passwordDigestBase64Str,nonce, cTime);
}
```
 #### 接收状态报告
```
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_0002.html)/[PHP](https://support.huaweicloud.com/devg-msgsms/sms_04_0003.html)/[Python](https://support.huaweicloud.com/devg-msgsms/sms_04_0004.html)/[C#](https://support.huaweicloud.com/devg-msgsms/sms_04_0005.html)/[Node.js](https://support.huaweicloud.com/devg-msgsms/sms_04_0008.html)  - 发送短信API  - 发送分批短信API  - 接收状态报告API  - 接收上行短信API  - 调测问题处理   | 语音通话 隐私保护通话 |
   
