【API调用】腾讯云短信

时间:2023-03-08 21:27:24

在之前介绍的火车票查询工具中,利用邮件和短信将查询结果推送给用户。免费短信的条数只有5条,用完之后只能单独使用邮件提醒。

最近发现腾讯云的福利,简单的介绍一下用法。

【API调用】腾讯云短信

腾讯云-》产品-》通信服务-》短信-》开通服务-》添加应用-》创建签名和模板-》等待审核通过-》按照Demo测试

【API调用】腾讯云短信【API调用】腾讯云短信

在整个流程中,最耗时的就是创建签名和模板,对个人来说只能选择app、公众号或小程序的方式进行申请,多亏之前折腾过一点小程序,从而闯关成功。

接下来查看官方Demo https://github.com/qcloudsms/qcloudsms/tree/master/demo/csharp

整理后的测试Demo

调用代码:

 using QcloudSms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleTest
{
class SmsSDKDemo
{
/// <summary>
/// appId
/// </summary>
private static int appId = 140xxxxx;
/// <summary>
/// appKey
/// </summary>
private static string appKey = "xxxxxxxxxxxxxxx";
/// <summary>
/// 接收手机号
/// </summary>
private static string phoneNumber = "xxxxxxxx";
/// <summary>
/// 短信模板ID
/// </summary>
private static int tmplateId = xxxxxxx; static void Main(string[] args)
{
try
{
SmsSingleSenderResult singleResult;
SmsSingleSender singleSender = new SmsSingleSender(appId, appKey); singleResult = singleSender.Send(SmsType.普通短信, phoneNumber, "");
Console.WriteLine(singleResult); List<string> templParams = new List<string>();
templParams.Add("G2619");
templParams.Add("二等座:23 无座:128");
singleResult = singleSender.SendWithParam(phoneNumber, tmplateId, templParams);
Console.WriteLine(singleResult);
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.Read();
}
}
}
 namespace QcloudSms
{
#region 短信类型枚举
/// <summary>
/// 短信类型枚举
/// </summary>
public enum SmsType
{
普通短信 = ,
营销短信 =
}
#endregion #region 单发
/// <summary>
/// 单发
/// </summary>
class SmsSingleSender
{
#region 变量
/// <summary>
/// appId
/// </summary>
private int appId;
/// <summary>
/// appkey
/// </summary>
private string appkey;
/// <summary>
/// url
/// </summary>
private string url = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms";
/// <summary>
/// util
/// </summary>
private SmsSenderUtil util = new SmsSenderUtil();
#endregion #region 构造
/// <summary>
/// 构造函数
/// </summary>
/// <param name="sdkappid"></param>
/// <param name="appkey"></param>
public SmsSingleSender(int sdkappid, string appkey)
{
this.appId = sdkappid;
this.appkey = appkey;
}
#endregion #region 普通单发短信接口
/// <summary>
/// 普通单发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名
/// </summary>
/// <param name="type">短信类型,0 为普通短信,1 营销短信</param>
/// <param name="phoneNumber">不带国家码的手机号</param>
/// <param name="msg">信息内容,必须与申请的模板格式一致,否则将返回错误</param>
/// <param name="extend">短信码号扩展号,格式为纯数字串,其他格式无效。默认没有开通</param>
/// <param name="ext">服务端原样返回的参数,可填空</param>
/// <returns>SmsSingleSenderResult</returns>
public SmsSingleSenderResult Send(SmsType type, string phoneNumber, string msg, string extend = "", string ext = "")
{
long random = util.GetRandom();
long curTime = util.GetCurTime(); // 按照协议组织 post 请求包体
JObject tel = new JObject();
tel.Add("nationcode", SmsSenderUtil.nationCode);
tel.Add("mobile", phoneNumber);
JObject data = new JObject();
data.Add("tel", tel);
data.Add("msg", msg);
data.Add("type", (int)type);
data.Add("sig", util.StrToHash(string.Format("appkey={0}&random={1}&time={2}&mobile={3}", appkey, random, curTime, phoneNumber)));
data.Add("time", curTime);
data.Add("extend", extend);
data.Add("ext", ext); string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random;
HttpWebRequest request = util.GetPostHttpConn(wholeUrl);
byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
request.ContentLength = requestData.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(requestData, , requestData.Length);
requestStream.Close(); // 接收返回包
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
string responseStr = streamReader.ReadToEnd();
streamReader.Close();
responseStream.Close();
SmsSingleSenderResult result;
if (HttpStatusCode.OK == response.StatusCode)
{
result = util.ResponseStrToSingleSenderResult(responseStr);
}
else
{
result = new SmsSingleSenderResult();
result.result = -;
result.errmsg = "http error " + response.StatusCode + " " + responseStr;
}
return result;
}
#endregion #region 指定模板单发
/// <summary>
/// 指定模板单发
/// </summary>
/// <param name="phoneNumber">不带国家码的手机号</param>
/// <param name="templId">模板 id</param>
/// <param name="templParams">模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数</param>
/// <param name="sign">短信签名,如果使用默认签名,该字段可缺省</param>
/// <param name="extend">扩展码,可填空</param>
/// <param name="ext">服务端原样返回的参数,可填空</param>
/// <returns>SmsSingleSenderResult</returns>
public SmsSingleSenderResult SendWithParam(string phoneNumber, int templId, List<string> templParams, string sign = "", string extend = "", string ext = "")
{
long random = util.GetRandom();
long curTime = util.GetCurTime(); // 按照协议组织 post 请求包体
JObject tel = new JObject();
tel.Add("nationcode", SmsSenderUtil.nationCode);
tel.Add("mobile", phoneNumber);
JObject data = new JObject();
data.Add("tel", tel);
data.Add("sig", util.CalculateSigForTempl(appkey, random, curTime, phoneNumber));
data.Add("tpl_id", templId);
data.Add("params", util.SmsParamsToJSONArray(templParams));
data.Add("sign", sign);
data.Add("time", curTime);
data.Add("extend", extend);
data.Add("ext", ext); string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random;
HttpWebRequest request = util.GetPostHttpConn(wholeUrl);
byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
request.ContentLength = requestData.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(requestData, , requestData.Length);
requestStream.Close(); // 接收返回包
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
string responseStr = streamReader.ReadToEnd();
streamReader.Close();
responseStream.Close();
SmsSingleSenderResult result;
if (HttpStatusCode.OK == response.StatusCode)
{
result = util.ResponseStrToSingleSenderResult(responseStr);
}
else
{
result = new SmsSingleSenderResult();
result.result = -;
result.errmsg = "http error " + response.StatusCode + " " + responseStr;
}
return result;
}
#endregion
}
#endregion #region 单发结果
/// <summary>
/// 单发结果
/// </summary>
class SmsSingleSenderResult
{
/// <summary>
/// 错误码,0 表示成功(计费依据),非 0 表示失败
/// </summary>
public int result { set; get; }
/// <summary>
/// 错误消息,result 非 0 时的具体错误信息
/// </summary>
public string errmsg { set; get; }
/// <summary>
/// 用户的 session 内容,腾讯 server 回包中会原样返回
/// </summary>
public string ext { set; get; }
/// <summary>
/// 本次发送标识 id,标识一次短信下发记录
/// </summary>
public string sid { set; get; }
/// <summary>
/// 短信计费的条数
/// </summary>
public int fee { set; get; }
/// <summary>
/// ToString()
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format("SmsSingleSenderResult\nresult {0}\nerrMsg {1}\next {2}\nsid {3}\nfee {4}", result, errmsg, ext, sid, fee);
}
}
#endregion #region 群发
/// <summary>
/// 群发
/// </summary>
class SmsMultiSender
{
#region 变量
/// <summary>
/// appId
/// </summary>
private int appId;
/// <summary>
/// appkey
/// </summary>
private string appkey;
/// <summary>
/// url
/// </summary>
private string url = "https://yun.tim.qq.com/v5/tlssmssvr/sendmultisms2";
/// <summary>
/// util
/// </summary>
private SmsSenderUtil util = new SmsSenderUtil();
#endregion #region 构造
/// <summary>
/// 构造
/// </summary>
/// <param name="sdkappid"></param>
/// <param name="appkey"></param>
public SmsMultiSender(int sdkappid, string appkey)
{
this.appId = sdkappid;
this.appkey = appkey;
}
#endregion #region 普通群发短信接口
/// <summary>
/// 普通群发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名
///【注意】 海外短信无群发功能
/// </summary>
/// <param name="type">短信类型,0 为普通短信,1 营销短信</param>
/// <param name="nationCode"></param>
/// <param name="phoneNumbers">不带国家码的手机号列表</param>
/// <param name="msg">信息内容,必须与申请的模板格式一致,否则将返回错误</param>
/// <param name="extend">扩展码,可填空</param>
/// <param name="ext">服务端原样返回的参数,可填空</param>
/// <returns>SmsMultiSenderResult</returns>
public SmsMultiSenderResult Send(SmsType type, List<string> phoneNumbers, string msg, string extend = "", string ext = "")
{
long random = util.GetRandom();
long curTime = util.GetCurTime(); // 按照协议组织 post 请求包体
JObject data = new JObject();
data.Add("tel", util.PhoneNumbersToJSONArray(SmsSenderUtil.nationCode, phoneNumbers));
data.Add("type", (int)type);
data.Add("msg", msg);
data.Add("sig", util.CalculateSig(appkey, random, curTime, phoneNumbers));
data.Add("time", curTime);
data.Add("extend", extend);
data.Add("ext", ext); string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random;
HttpWebRequest request = util.GetPostHttpConn(wholeUrl);
byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
request.ContentLength = requestData.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(requestData, , requestData.Length);
requestStream.Close(); // 接收返回包
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
string responseStr = streamReader.ReadToEnd();
streamReader.Close();
responseStream.Close();
SmsMultiSenderResult result;
if (HttpStatusCode.OK == response.StatusCode)
{
result = util.ResponseStrToMultiSenderResult(responseStr);
}
else
{
result = new SmsMultiSenderResult();
result.result = -;
result.errmsg = "http error " + response.StatusCode + " " + responseStr;
}
return result;
}
#endregion #region 指定模板群发
/// <summary>
/// 指定模板群发
/// 【注意】海外短信无群发功能
/// </summary>
/// <param name="phoneNumbers">不带国家码的手机号列表</param>
/// <param name="templId"> 模板 id</param>
/// <param name="templParams">模板参数列表</param>
/// <param name="sign"> 签名,如果填空,系统会使用默认签名</param>
/// <param name="extend">扩展码,可以填空</param>
/// <param name="ext">服务端原样返回的参数,可以填空</param>
/// <returns> SmsMultiSenderResult</returns>
public SmsMultiSenderResult SendWithParam(List<string> phoneNumbers, int templId, List<string> templParams, string sign = "", string extend = "", string ext = "")
{
long random = util.GetRandom();
long curTime = util.GetCurTime(); // 按照协议组织 post 请求包体
JObject data = new JObject();
data.Add("tel", util.PhoneNumbersToJSONArray(SmsSenderUtil.nationCode, phoneNumbers));
data.Add("sig", util.CalculateSigForTempl(appkey, random, curTime, phoneNumbers));
data.Add("tpl_id", templId);
data.Add("params", util.SmsParamsToJSONArray(templParams));
data.Add("sign", sign);
data.Add("time", curTime);
data.Add("extend", extend);
data.Add("ext", ext); string wholeUrl = url + "?sdkappid=" + appId + "&random=" + random;
HttpWebRequest request = util.GetPostHttpConn(wholeUrl);
byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
request.ContentLength = requestData.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(requestData, , requestData.Length);
requestStream.Close(); // 接收返回包
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
string responseStr = streamReader.ReadToEnd();
streamReader.Close();
responseStream.Close();
SmsMultiSenderResult result;
if (HttpStatusCode.OK == response.StatusCode)
{
result = util.ResponseStrToMultiSenderResult(responseStr);
}
else
{
result = new SmsMultiSenderResult();
result.result = -;
result.errmsg = "http error " + response.StatusCode + " " + responseStr;
}
return result;
}
#endregion
}
#endregion #region 群发结果
/// <summary>
/// 群发结果
/// </summary>
class SmsMultiSenderResult
{
public class Detail
{
/// <summary>
/// 错误码,0 表示成功(计费依据),非 0 表示失败
/// </summary>
public int result { get; set; }
/// <summary>
/// 错误消息,result 非 0 时的具体错误信息
/// </summary>
public string errmsg { get; set; }
/// <summary>
/// 手机号码
/// </summary>
public string mobile { get; set; }
/// <summary>
/// 国家码
/// </summary>
public string nationcode { get; set; }
/// <summary>
/// 本次发送标识 id,标识一次短信下发记录
/// </summary>
public string sid { get; set; }
/// <summary>
/// 短信计费的条数
/// </summary>
public int fee { get; set; }
/// <summary>
/// ToString()
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format(
"\tDetail result {0} errmsg {1} mobile {2} nationcode {3} sid {4} fee {5}",
result, errmsg, mobile, nationcode, sid, fee);
}
} public int result;
public string errmsg = "";
public string ext = "";
public IList<Detail> detail; public override string ToString()
{
if (null != detail)
{
return String.Format(
"SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\ndetail:\n{3}",
result, errmsg, ext, String.Join("\n", detail));
}
else
{
return String.Format(
"SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\n",
result, errmsg, ext);
}
}
}
#endregion #region 公共类
/// <summary>
/// 公共类
/// </summary>
class SmsSenderUtil
{
/// <summary>
/// 国家码
/// </summary>
public static string nationCode = "";
/// <summary>
/// 随机数生成器
/// </summary>
private Random random = new Random(); #region GetPostHttpConn
/// <summary>
/// GetPostHttpConn
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public HttpWebRequest GetPostHttpConn(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
return request;
}
#endregion #region 生成随机数
/// <summary>
/// 生成随机数
/// </summary>
/// <returns></returns>
public long GetRandom()
{
return random.Next() % + ;
}
#endregion #region 获取请求发起时间
/// <summary>
/// 获取请求发起时间,
/// unix 时间戳(单位:秒),如果和系统时间相差超过 10 分钟则会返回失败
/// </summary>
/// <returns></returns>
public long GetCurTime()
{
Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(, , ))).TotalSeconds;
return unixTimestamp;
}
#endregion #region 字符串转SHA256
/// <summary>
/// 字符串转SHA256
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string StrToHash(string str)
{
SHA256 sha256 = SHA256Managed.Create();
byte[] resultByteArray = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(str));
return ByteArrayToHex(resultByteArray);
} /// <summary>
/// 将二进制的数值转换为 16 进制字符串,如 "abc" => "616263"
/// </summary>
/// <param name="byteArray"></param>
/// <returns></returns>
private static string ByteArrayToHex(byte[] byteArray)
{
string returnStr = "";
if (byteArray != null)
{
for (int i = ; i < byteArray.Length; i++)
{
returnStr += byteArray[i].ToString("x2");
}
}
return returnStr;
}
#endregion #region 将单发回包解析成结果对象
/// <summary>
/// 将单发回包解析成结果对象
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public SmsSingleSenderResult ResponseStrToSingleSenderResult(string str)
{
SmsSingleSenderResult result = JsonConvert.DeserializeObject<SmsSingleSenderResult>(str);
return result;
}
#endregion #region 将群发回包解析成结果对象
/// <summary>
/// 将群发回包解析成结果对象
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public SmsMultiSenderResult ResponseStrToMultiSenderResult(string str)
{
SmsMultiSenderResult result = JsonConvert.DeserializeObject<SmsMultiSenderResult>(str);
return result;
}
#endregion #region List<string>转JArray
/// <summary>
/// List<string>转JArray
/// </summary>
/// <param name="templParams"></param>
/// <returns></returns>
public JArray SmsParamsToJSONArray(List<string> templParams)
{
JArray smsParams = new JArray();
foreach (string templParamsElement in templParams)
{
smsParams.Add(templParamsElement);
}
return smsParams;
}
#endregion #region PhoneNumbersToJSONArray
/// <summary>
/// PhoneNumbersToJSONArray
/// </summary>
/// <param name="nationCode"></param>
/// <param name="phoneNumbers"></param>
/// <returns></returns>
public JArray PhoneNumbersToJSONArray(string nationCode, List<string> phoneNumbers)
{
JArray tel = new JArray();
int i = ;
do
{
JObject telElement = new JObject();
telElement.Add("nationcode", nationCode);
telElement.Add("mobile", phoneNumbers.ElementAt(i));
tel.Add(telElement);
} while (++i < phoneNumbers.Count);
return tel;
}
#endregion #region 计算App凭证
/*
"sig" 字段根据公式 sha256(appkey=$appkey&random=$random&time=$time&mobile=$mobile)生成
*/
public string CalculateSigForTempl(string appkey, long random, long curTime, List<string> phoneNumbers)
{
string phoneNumbersString = phoneNumbers.ElementAt();
for (int i = ; i < phoneNumbers.Count; i++)
{
phoneNumbersString += "," + phoneNumbers.ElementAt(i);
}
return StrToHash(String.Format(
"appkey={0}&random={1}&time={2}&mobile={3}",
appkey, random, curTime, phoneNumbersString));
} public string CalculateSigForTempl(string appkey, long random, long curTime, string phoneNumber)
{
List<string> phoneNumbers = new List<string>();
phoneNumbers.Add(phoneNumber);
return CalculateSigForTempl(appkey, random, curTime, phoneNumbers);
} public string CalculateSig(string appkey, long random, long curTime, List<string> phoneNumbers)
{
string phoneNumbersString = phoneNumbers.ElementAt();
for (int i = ; i < phoneNumbers.Count; i++)
{
phoneNumbersString += "," + phoneNumbers.ElementAt(i);
}
return StrToHash(String.Format(
"appkey={0}&random={1}&time={2}&mobile={3}",
appkey, random, curTime, phoneNumbersString));
}
#endregion
}
#endregion
}

QcloudSms

demo下载路径为:https://files.cnblogs.com/files/LikeHeart/ConsoleTest.zip