更新时间:2024-06-21 GMT+08:00

Go

样例

发送短信发送分批短信

接收状态报告

环境要求

go1.17.1,IntelliJ IDEA 2021.1.3安装插件(Go 211.7628.1)

  • 发送短信为单模板群发短信示例,发送分批短信为多模板群发短信示例。
  • 本文档所述Demo在提供服务的过程中,可能会涉及个人数据的使用,建议您遵从国家的相关法律采取足够的措施,以确保用户的个人数据受到充分的保护。
  • 本文档所述Demo仅用于功能演示,不允许客户直接进行商业使用。
  • 本文档信息仅供参考,不构成任何要约或承诺。

参考API签名SDK与demo,点击下载其中的SDK与Demo。将下列代码样例替换demo.go文件内容即可。

将首层go.mod文件内容修改为:
1
2
3
4
5
6
7
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

发送短信示例

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
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.ap-southeast-1.myhuaweicloud.com:443/sms/batchSendSms/v1" //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI
   sender := "csms12345678"                                    //中国大陆短信签名通道号或全球短信通道号
   templateId := "8ff55eac1d0b478ab3c06c3c6a492300"               //模板ID

   //条件必填,中国大陆短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
   //全球短信不用关注该参数
   signature := "华为云短信测试" //签名名称

   //必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
   receiver := "+86151****6789" //短信接收人号码

   //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
   statusCallBack := ""

   /*
    * 选填,使用无变量模板时请赋空值 string templateParas = "";
    * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为'["369751"]'
    * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,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
}

发送分批短信示例

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main

import (
   "bytes"
   "crypto/tls"
   "encoding/json"
   "fmt"
   core "huaweicloud.com/apig/signer"
   "io/ioutil"
   "net/http"
)

func main() {
      //必填,请参考"开发准备"获取如下数据,替换为实际值
   apiAddress := "https://smsapi.ap-southeast-1.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{}
    * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为[]string{"369751"}
    * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,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
}

接收状态报告

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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 := "orgCode=E200027&sequence=1&total=1&updateTime=2018-10-31T08%3A43%3A41Z&source=2&smsMsgId=2ea20735-f856-4376-afbf-570bd70a46ee_11840135&status=RTE_ERR";
    //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];
    }
    /**
    * Example: 此处已解析status为例,请按需解析所需参数并自行实现相关处理
    * 
    * 'smsMsgId': 短信唯一标识
    * 'total': 长短信拆分条数
    * 'sequence': 拆分后短信序号
    * 'source': 状态报告来源
    * 'updateTime': 资源更新时间
    * 'status': 状态报告枚举值
    * 'orgCode': 状态码
    */
    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"])
        fmt.Println("Failed orgCode:  " + keyValues["orgCode"])
    }
}