美文网首页菜鸟学编程.NET
使用阿里云的短信服务发送短信

使用阿里云的短信服务发送短信

作者: 菜鸟飞不动 | 来源:发表于2019-04-11 00:02 被阅读12次

    原文地址使用阿里云的短信服务发送短信

    在给客户开发一个信息发送功能的时候,需要涉及到短信的发送,短信发送一般不同的厂商提供的接口不同,处理方式也不太一样,之前用的一个厂商的,提供了一个封装类就很容易发送短息,因此都是基于HTTP协议做的一个数据发送而已,接触阿里云的短信服务器后,发现阿里云还增加了非常多的参数,其中包括一些秘钥和签名的内容。短信发送由于比较敏感原因,大多数应用场景是验证码或者一些固定的信息提醒,因此厂商都要求客户按预定的模板来发送,这样限制了短信的应用场景,只能根据业务进行消息定制了。本篇随笔主要介绍阿里云的短信服务的发送处理。

    1、短信发送的处理介绍

    在短信发送中,阿里云提供自己的SDK封装,以降低使用的难度,不过需要引入它提供的SDK类库;本篇随笔主要介绍基于HTTP方式进行自行的封装处理,这部分代码我从网上摘录并进行一定的调整,测试成功。

    使用阿里云的短信服务,需要注册登录自己的阿里云控制台,然后进入AccessKeys的处理界面

    img

    然后系统会提示需要创建一个新的Key(如果没有的话就创建,否则使用已有的即可)

    img

    这里我们获取到AccessKey ID 和Access Key Secret两个关键信息,需要用在数据签名的里面的。

    另外我们需要创建一个SignName,也就是签名,一般为我们短信提示的公司名称,如【广州爱奇迪】这样的字样。

    img

    短信是基于模板的,阿里云不能发送随意的内容,因此只能基于模板发送,如验证码或者业务消息,有点类似微信的模板消息了,因此里面可以添加变量发送的。

    记得我以前写过一个关于动态变量的信息发送的文章《一个包含动态变量的短信模板设计分析》,就是介绍如何处理变量模板消息的。

    阿里云默认提供了一些基础模板,如下所示。

    img

    一般我们业务可能还需要定制一些业务消息,那么需要审核通过才可以使用新增的模板消息。

    短信的发送可以利用API接口进行发送,如下所示是它的API说明

    img

    如果需要采集用户的回复信息,如一些随访记录,那么需要做一个接口的处理,如下所示。

    img

    发送短信的API接口详细说明如下所示。

    img

    其实请求信息比上面列出的信息多很多,包括秘钥和数据加密信息等的处理,下面详细给出代码说明。

    2、模板消息发送

    有了上面的信息介绍,我们大概了解了短信消息发送的处理规则了。

    实际上,发送信息的时候,我们可能需要添加很多参数信息,如下代码所示。

                Dictionary<string, string> keyValues = new Dictionary<string, string>();//声明一个字典
                //1.系统参数
                keyValues.Add("SignatureMethod", "HMAC-SHA1");
                keyValues.Add("SignatureNonce", Guid.NewGuid().ToString());
                keyValues.Add("AccessKeyId", AccessKeyId);
                keyValues.Add("SignatureVersion", "1.0");
                keyValues.Add("Timestamp", nowDate);
                keyValues.Add("Format", "Json");//可换成xml
    
                //2.业务api参数
                keyValues.Add("Action", "SendSms");
                keyValues.Add("Version", "2017-05-25");
                keyValues.Add("RegionId", "cn-hangzhou");
                keyValues.Add("PhoneNumbers", mobile);
                keyValues.Add("SignName", SignName);
                keyValues.Add("TemplateParam", "{\"code\":\"" + code + "\"}");
                keyValues.Add("TemplateCode", templateCode);
                keyValues.Add("OutId", "123");
    

    具体我们来贴出不用SDK的短信发送辅助类,如下代码所示。

        /// <summary>
        /// 阿里短信发送
        /// </summary>
        public class SmsHelper
        {
            private const string endpoint = "dysmsapi.aliyuncs.com";
            private const string AccessKeyId = "你的秘钥键";
            private const string AccessKeySecret = "你的秘钥值";
            private const string SignName = "广州爱奇迪";
    
            /// <summary>
            /// 短信验证码
            /// </summary>
            /// <param name="mobile"></param>
            /// <param name="code"></param>
            /// <returns></returns>
            public static string SendSms(string mobile, int code, string templateCode = "SMS_126645400")
            {
                string nowDate = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'");//GTM时间
                Dictionary<string, string> keyValues = new Dictionary<string, string>();//声明一个字典
                //1.系统参数
                keyValues.Add("SignatureMethod", "HMAC-SHA1");
                keyValues.Add("SignatureNonce", Guid.NewGuid().ToString());
                keyValues.Add("AccessKeyId", AccessKeyId);
                keyValues.Add("SignatureVersion", "1.0");
                keyValues.Add("Timestamp", nowDate);
                keyValues.Add("Format", "Json");//可换成xml
    
                //2.业务api参数
                keyValues.Add("Action", "SendSms");
                keyValues.Add("Version", "2017-05-25");
                keyValues.Add("RegionId", "cn-hangzhou");
                keyValues.Add("PhoneNumbers", mobile);
                keyValues.Add("SignName", SignName);
                keyValues.Add("TemplateParam", "{\"code\":\"" + code + "\"}");
                keyValues.Add("TemplateCode", templateCode);
                keyValues.Add("OutId", "123");
    
                //3.去除签名关键字key
                if (keyValues.ContainsKey("Signature"))
                {
                    keyValues.Remove("Signature");
                }
    
                //4.参数key排序
                Dictionary<string, string> ascDic = keyValues.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value.ToString());
                //5.构造待签名的字符串
                StringBuilder builder = new StringBuilder();
                foreach (var item in ascDic)
                {
                    if (item.Key == "SignName")
                    {
                    }
                    else
                    {
                        builder.Append("&").Append(specialUrlEncode(item.Key)).Append("=").Append(specialUrlEncode(item.Value));
                    }
                    if (item.Key == "RegionId")
                    {
                        builder.Append("&").Append(specialUrlEncode("SignName")).Append("=").Append(specialUrlEncode(keyValues["SignName"]));
                    }
                }
                string sorteQueryString = builder.ToString().Substring(1);
    
                StringBuilder stringToSign = new StringBuilder();
                stringToSign.Append("GET").Append("&");
                stringToSign.Append(specialUrlEncode("/")).Append("&");
                stringToSign.Append(specialUrlEncode(sorteQueryString));
    
                string Sign = MySign(AccessKeySecret + "&", stringToSign.ToString());
                //6.签名最后也要做特殊URL编码
                string signture = specialUrlEncode(Sign);
    
                //最终打印出合法GET请求的URL
                string url = string.Format("http://{0}/?Signature={1}{2}", endpoint, signture, builder);
                string result = GetHtmlFormUrl(url);
                return result;
            }
    
    
            /// <summary>
            /// 短信接口C#调用方法
            /// </summary>
            /// <param name="url"></param>
            /// <returns></returns>
            private static string GetHtmlFormUrl(string url)
            {
                string strRet = null;
                if (url == null || url.Trim().ToString() == "")
                {
                    return strRet;
                }
                string targeturl = url.Trim().ToString();
                try
                {
                    HttpWebRequest hr = (HttpWebRequest)WebRequest.Create(targeturl);
                    hr.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
                    hr.Method = "GET";
                    hr.Timeout = 30 * 60 * 1000;
                    WebResponse hs = hr.GetResponse();
                    Stream sr = hs.GetResponseStream();
                    StreamReader ser = new StreamReader(sr, Encoding.UTF8);
    
                    strRet = MessageHandle(ser.ReadToEnd());
                }
                catch (Exception ex)
                {
                    strRet = "短信发送失败!" + ex.Message;
                }
                return strRet;
            }
    
            /// <summary>
            /// 验证手机号码是否合法
            /// </summary>
            /// <param name="mobile">电话号码</param>
            /// <returns></returns>
            public static bool IsMobile(string mobile)
            {
                return System.Text.RegularExpressions.Regex.IsMatch(mobile, @"^1[3|4|5|7|8][0-9]\d{8}$");
            }
    
            /// <summary>
            /// URL编码
            /// </summary>
            /// <param name="value"></param>
            /// <returns></returns>
            private static string specialUrlEncode(string temp)
            {
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < temp.Length; i++)
                {
                    string t = temp[i].ToString();
                    string k = HttpUtility.UrlEncode(t, Encoding.UTF8);
                    if (t == k)
                    {
                        stringBuilder.Append(t);
                    }
                    else
                    {
                        stringBuilder.Append(k.ToUpper());
                    }
                }
                return stringBuilder.ToString().Replace("+", "%20").Replace("*", "%2A").Replace("%7E", "~");
            }
    
            /// <summary>
            /// HMACSHA1签名
            /// </summary>
            /// <param name="accessSecret"></param>
            /// <param name="stringToSign"></param>
            /// <returns></returns>
            private static string MySign(string accessSecret, string stringToSign)
            {
                try
                {
                    var hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(accessSecret));
                    var dataBuffer = Encoding.UTF8.GetBytes(stringToSign);
                    var hashBytes = hmacsha1.ComputeHash(dataBuffer);
                    string stringbyte = BitConverter.ToString(hashBytes, 0).Replace("-", string.Empty).ToLower();
                    byte[] bytes = strToToHexByte(stringbyte);
                    return Convert.ToBase64String(bytes);
                }
                catch (Exception ex)
                {
    
                    throw ex;
                }
            }
            /// <summary>
            /// 字符串转16进制字节数组
            /// </summary>
            /// <param name="hexString"></param>
            /// <returns></returns>
            private static byte[] strToToHexByte(string hexString)
            {
                hexString = hexString.Replace(" ", "");
                if ((hexString.Length % 2) != 0)
                    hexString += " ";
                byte[] returnBytes = new byte[hexString.Length / 2];
                for (int i = 0; i < returnBytes.Length; i++)
                    returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                return returnBytes;
            }
    
            /// <summary>
            /// 消息处理机制
            /// </summary>
            /// <param name="str"></param>
            /// <returns></returns>
            private static string MessageHandle(string str)
            {
                MessageModel message = JsonConvert.DeserializeObject<MessageModel>(str);
                string result = "";
                switch (message.Code)
                {
                    case "OK":
                        result = "短信发送成功!";
                        break;
                    case "isp.RAM_PERMISSION_DENY":
                        result = "RAM权限DENY";
                        break;
                    case "isv.OUT_OF_SERVICE":
                        result = "业务停机";
                        break;
                    case "isv.PRODUCT_UN_SUBSCRIPT":
                        result = "未开通云通信产品的阿里云客户";
                        break;
                    case "isv.PRODUCT_UNSUBSCRIBE":
                        result = "产品未开通";
                        break;
                    case "isv.ACCOUNT_NOT_EXISTS":
                        result = "账户不存在";
                        break;
                    case "isv.ACCOUNT_ABNORMAL":
                        result = "账户异常    ";
                        break;
                    case "isv.SMS_TEMPLATE_ILLEGAL":
                        result = "短信模板不合法";
                        break;
                    case "isv.SMS_SIGNATURE_ILLEGAL":
                        result = "短信签名不合法";
                        break;
                    case "isv.INVALID_PARAMETERS":
                        result = "参数异常";
                        break;
                    case "isv.MOBILE_NUMBER_ILLEGAL":
                        result = "非法手机号";
                        break;
                    case "isv.MOBILE_COUNT_OVER_LIMIT":
                        result = "手机号码数量超过限制";
                        break;
                    case "isv.TEMPLATE_MISSING_PARAMETERS":
                        result = "模板缺少变量";
                        break;
                    case "isv.BUSINESS_LIMIT_CONTROL":
                        result = "业务限流";
                        break;
                    case "isv.INVALID_JSON_PARAM":
                        result = "JSON参数不合法,只接受字符串值";
                        break;
                    case "isv.PARAM_LENGTH_LIMIT":
                        result = "参数超出长度限制";
                        break;
                    case "isv.PARAM_NOT_SUPPORT_URL":
                        result = "不支持URL";
                        break;
                    case "isv.AMOUNT_NOT_ENOUGH":
                        result = "账户余额不足";
                        break;
                    case "isv.TEMPLATE_PARAMS_ILLEGAL":
                        result = "模板变量里包含非法关键字";
                        break;
                }
                return result;
            }
    
        }
    
        internal class MessageModel
        {
            public string RequestId { get; set; }
            public string Code { get; set; }
            public string Message { get; set; }
        }
    

    上面代码不是我原创,声明一下,我做了一些修改调整而已,方便辅助类的使用,我们输入我们的企业的秘钥键值,然后发送测试短信即可。

                string tel = "18620292076";
                string result = SmsHelper.SendSms(tel, 123456);
                Console.WriteLine(result);
    

    发送测试,3~5秒就可以收到验证码信息的提示了,如下所示。

    img

    以上就是短信消息的发送,希望对使用阿里云短信服务的开发人员有所帮助,辅助类直接就可以使用了

    相关文章

      网友评论

        本文标题:使用阿里云的短信服务发送短信

        本文链接:https://www.haomeiwen.com/subject/irvaiqtx.html