阿里大于是阿里通信旗下产品,融合了三大运营商的通信能力,提供包括短信、语音、流量直充、私密专线、店铺手机号等个性化服务。每条四分五,价钱还算公道,经老农测试,响应速度非常快,基本上是秒到。官方文档提供了JAVA、.NET、PHP、Python、C/C++、NodeJS 等语言的 Demo,唯独没有 Dephi,但这也不能怪马云,毕竟 Delphi 实在太小众了。

   最近用 Delphi 写个 App,注册用户需要用到手机短信验证,于是找到的阿里大于,使用 Delphi 10.1 berlin 写了个简单的 Demo 并测试通过,现在交出代码:

/// <author>全能地图(QQ:64445322)</author>
/// <summary>
/// 利用阿里大于接口发短信
/// 阿里大于网址:http://www.alidayu.com
/// 阿里大于短信接口文档:https://api.alidayu.com/doc2/apiDetail.htm?apiId=25450
/// </summary>
/// <param name="AppKey">TOP分配给应用的AppKey</param>
/// <param name="AppSecret">AppSecret</param>
/// <param name="ReceiveNumber">接收手机号码</param>
/// <param name="FreeSignName">短信签名,传入的短信签名必须是在阿里大于“管理中心-短信签名管理”中的可用签名</param>
/// <param name="TemplateCode">短信模板ID</param>
/// <param name="TemplateContent">短信模板变量,例如:{"code":"1234","product":"alidayu"}</param>
/// <param name="ResultMsg">下发结果消息</param>
/// <returns>是否成功,True = 成功 ,false = 失败</returns>
function SendSMS(const AppKey, AppSecret, ReceiveNumber, FreeSignName, TemplateCode, TemplateContent: string; var ResultMsg: string): Boolean;

  // 签名算法:http://open.taobao.com/doc2/detail.htm?articleId=101617&docType=1&treeId=1
  function MakeSign(const AParams: TStringList; const AppSecret: string): string;
  var
    I: Integer;
    Data: string;
  begin
    // 参数排序
    AParams.Sort;

    // 参数拼接
    Data := \'\';
    for I := 0 to AParams.Count - 1 do
      Data := Data + AParams[I].Replace(\'=\', \'\');

    // HMAC 算法
    Result := THashMD5.GetHMAC(Data, AppSecret).ToUpper;
  end;

var
  HTTP: TNetHTTPClient;
  JO: TJSONObject;
  Params: TStringList;
  Response: string;
begin
  Result := False;

  HTTP := TNetHTTPClient.Create(nil);
  Params := TStringList.Create();
  try
    Params.Values[\'app_key\'] := AppKey;
    Params.Values[\'format\'] := \'json\';
    Params.Values[\'method\'] := \'alibaba.aliqin.fc.sms.num.send\';
    Params.Values[\'sign_method\'] := \'hmac\';
    Params.Values[\'timestamp\'] := FormatDateTime(\'yyyy-MM-dd HH:mm:ss\', Now);
    Params.Values[\'v\'] := \'2.0\';
    Params.Values[\'sms_type\'] := \'normal\';
    Params.Values[\'sms_free_sign_name\'] := FreeSignName;
    Params.Values[\'rec_num\'] := ReceiveNumber;
    Params.Values[\'sms_template_code\'] := TemplateCode;
    Params.Values[\'sms_param\'] := TemplateContent;
    Params.Values[\'sign\'] := MakeSign(Params, AppSecret);

    HTTP.ContentType := \'application/x-www-form-urlencoded\';
    try
      Response := HTTP.Post(\'https://eco.taobao.com/router/rest\', Params).ContentAsString();
    except
      on E: Exception do
      begin
        ResultMsg := E.Message;
        Exit;
      end;
    end;

    JO := TJSONObject.ParseJSONValue(Response) as TJSONObject;
    try
      if JO <> nil then
      begin
        if JO.TryGetValue<string>(\'alibaba_aliqin_fc_sms_num_send_response.result.success\', ResultMsg) then
          Result := ResultMsg.ToUpper = \'TRUE\'
        else if JO.TryGetValue<string>(\'error_response.msg\', ResultMsg) then
          Result := False;
      end;

    finally
      JO.Free;
    end;

  finally
    HTTP.Free;
    Params.Free;
  end;

end;

D7的版本

function SendSMS(const AppKey, AppSecret, ReceiveNumber, FreeSignName, TemplateCode, TemplateContent: string; var ResultMsg: string): Boolean;

  function GetStringMD5(const AInPut: string): string;
  var
    MD5: TIdHashMessageDigest5;
    Digest: T4x4LongWordRecord;
  begin
    MD5 := TIdHashMessageDigest5.Create;
    try
      Digest := MD5.HashValue(AInPut);
      Result := MD5.AsHex(Digest);
    finally
      MD5.Free;
    end;
  end;

// 签名算法:http://open.taobao.com/doc2/detail.htm?articleId=101617&docType=1&amp;treeId=1
  function MakeSign(const AParams: TStringList; const AppSecret: string): string;
  var
    I: Integer;
    Data: string;
  begin
    // 参数排序
    AParams.Sort;
    // 参数拼接
    Data := \'\';
    for I := 0 to AParams.Count - 1 do
      Data := Data + StringReplace(AParams[I], \'=\', \'\', [rfReplaceAll]);
    // MD5 算法
    Result := GetStringMD5(AppSecret + Data + AppSecret);
  end;

var
  HTTP: TIdHTTP;
  Params: TStringList;
  Response: string;
  JsonObject: ISuperObject;
begin
  Result := False;

  HTTP := TIdHTTP.Create(nil);
  Params := TStringList.Create();
  try
    Params.Values[\'app_key\'] := AppKey;
    Params.Values[\'format\'] := \'json\';
    Params.Values[\'method\'] := \'alibaba.aliqin.fc.sms.num.send\';
    Params.Values[\'sign_method\'] := \'md5\';
    Params.Values[\'timestamp\'] := FormatDateTime(\'yyyy-MM-dd HH:mm:ss\', Now);
    Params.Values[\'v\'] := \'2.0\';
    Params.Values[\'sms_type\'] := \'normal\';
    Params.Values[\'sms_free_sign_name\'] := UTF8Encode(FreeSignName);
    Params.Values[\'rec_num\'] := ReceiveNumber;
    Params.Values[\'sms_template_code\'] := TemplateCode;
    Params.Values[\'sms_param\'] := UTF8Encode(TemplateContent);
    Params.Values[\'sign\'] := MakeSign(Params, AppSecret);

    HTTP.HandleRedirects := True;
    HTTP.Request.AcceptCharSet := \'utf-8\';
    HTTP.Request.ContentType := \'application/x-www-form-urlencoded\';
    try
      Response := HTTP.Post(\'http://gw.api.taobao.com/router/rest\', Params);
    except
      on E: Exception do
      begin
        ResultMsg := E.Message;
        Exit;
      end;
    end;

    JsonObject := SO(Response);
    if JsonObject <> nil then
    begin
      ResultMsg := JsonObject.S[\'alibaba_aliqin_fc_sms_num_send_response.result.success\'];
      if ResultMsg <> \'\' then
        Result := UpperCase(ResultMsg) = \'TRUE\'
      else
      begin
        ResultMsg := JsonObject.S[\'error_response.msg\'];
        Result := False;
      end;
    end;

  finally
    HTTP.Free;
    Params.Free;
  end;

end;