대규모 온라인 쇼핑 시스템에서는 회원이 대금 상환 결제 방식을 선택할 수 있도록 하는 것 외에도 보다 편리하고 빠른 온라인 결제 방식도 제공해야 합니다. 온라인 상점이 회원에게 웹사이트에서 직접 현금 계좌를 개설하는 기능을 제공할 만큼 여력이 부족한 경우 주문 정보를 Alipay로 전송하여 회원이 Alipay에서 결제할 수 있도록 할 수 있습니다. 물론, 회원이 홈페이지에서 직접 현금계좌를 개설할 수 있다고 하더라도 알리페이 결제 기능을 제공하는 것은 편리하고 빠른 결제수단으로 고객에게 보다 다양한 결제수단을 제공할 수 있습니다.
우선 온라인 쇼핑 시스템은 본 쇼핑 웹사이트에서
Alipay 웹사이트에 업로드된 주문 정보가 올바르게 수신될 수 있도록 Alipay와 협력 계약을 체결해야 합니다.
회원이 쇼핑 웹사이트에서 일련의 상품을 구매하고 Alipay 결제 방법을 선택하면 쇼핑 시스템에서 회원의 쇼핑 주문 정보를 Alipay로 전달하고 웹사이트 페이지도 Alipay 결제로 리디렉션됩니다. 페이지. 이때 Alipay 페이지는 Alipay가 주문 정보를 올바르게 수신했는지 확인하기 위해 이 웹사이트에 확인 메시지를 보냅니다.
회원이 Alipay 웹사이트에서 결제를 완료하면 웹사이트 페이지가 이 쇼핑 웹사이트로 다시 이동합니다. 동시에 Alipay는 결제된 주문 정보를 이 웹사이트로 다시 전송하여 필요한 사항을 수정합니다. 이 쇼핑 웹사이트의 데이터베이스입니다. 또한 이 웹사이트는 시스템이 지불 주문 정보를 올바르게 수신했으며 데이터 처리를 완료했음을 Alipay에 알리기 위해 Alipay 웹사이트에 반환 메시지를 보내야 합니다.
Alipay 웹사이트에 주문 정보를 전송할 때 주요 매개변수의 의미:
게이트웨이: 결제 인터페이스
서비스: 어떤 인터페이스가 어떤 기능을 구현하는지 식별
seller_email : 가맹점 계약시 알리페이 계정, 즉 결제용 알리페이 계정
key : 보안인증코드, 파트너
partner : 가맹점ID, 파트너ID
가 있는 그룹인 보안인증번호
sign_type : 암호화 유형
_input_charset: 인코딩 유형
show_url: 표시 주소, 즉 알리페이 페이지 상품명 옆 '상세정보' 링크 주소
out_trade_no: 회원 주문번호, 주문번호 이 시스템에서 고유해야 합니다.
제목: 제품 이름, 주문 이름으로도 알려져 있습니다. 이 인터페이스는 한 가지 결제만 할 수 있는 단일 항목이 아닙니다.
본문: 제품 설명, 즉, 비고
total_fee: 제품 가격, 총 주문 금액이라고도 합니다.
소스 코드 분석(C#):
먼저 알림 페이지(Notify.aspx)와 반품 페이지(Return) .aspx)은 Alipay에서 반환된 정보를 수락 및 확인하고 데이터베이스에서 해당 주문 정보를 수정하기 위해 생성되어야 합니다.
using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Text; using System.Collections.Specialized; using System.IO; using Gateway; /// <summary> /// 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格。 /// 该页面称作“通知页”,是异步被支付宝服务器所调用。 /// 当支付宝的订单状态改变时,支付宝服务器则会自动调用此页面,因此请做好自身网站订单信息与支付宝上的订单的同步工作 /// </summary> public partial class Alipay_Notify : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string alipayNotifyURL = "https://www.alipay.com/cooperate/gateway.do?service=notify_verify"; //string alipayNotifyURL = "http://notify.alipay.com/trade/notify_query.do?";//此路径是在上面链接地址无法起作用时替换使用。 string partner = ""; //partner合作伙伴id(必须填写) string key = ""; //partner 的对应交易安全校验码(必须填写) string _input_charset = "utf-8";//编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。 alipayNotifyURL = alipayNotifyURL + "&partner=" + partner + "¬ify_id=" + Request.Form["notify_id"]; //获取支付宝ATN返回结果,true是正确的订单信息,false 是无效的 string responseTxt = AliPay.Get_Http(alipayNotifyURL, 120000); //*******加密签名程序开始******* int i; NameValueCollection coll; //Load Form variables into NameValueCollection variable. coll = Request.Form; // Get names of all forms into a string array. String[] requestarr = coll.AllKeys; //进行排序; string[] Sortedstr = AliPay.BubbleSort(requestarr); //构造待md5摘要字符串 ; StringBuilder prestr = new StringBuilder(); for (i = 0; i < Sortedstr.Length; i++) { if (Request.Form[Sortedstr[i]] != "" && Sortedstr[i] != "sign" && Sortedstr[i] != "sign_type") { if (i == Sortedstr.Length - 1) { prestr.Append(Sortedstr[i] + "=" + Request.Form[Sortedstr[i]]); } else { prestr.Append(Sortedstr[i] + "=" + Request.Form[Sortedstr[i]] + "&"); } } } prestr.Append(key); string mysign = AliPay.GetMD5(prestr.ToString(), _input_charset); //*******加密签名程序结束******* string sign = Request.Form["sign"]; if (mysign == sign && responseTxt == "true") //验证支付发过来的消息,签名是否正确,只要成功进如这个判断里,则表示该页面已被支付宝服务器成功调用 //但判断内出现自身编写的程序相关错误导致通知给支付宝并不是发送success的消息或没有更新客户自身的数据库的情况,请自身程序编写好应对措施,否则查明原因时困难之极 { if (Request.Form["trade_status"] == "WAIT_BUYER_PAY")// 判断支付状态_等待买家付款(文档中有枚举表可以参考) { //更新自己数据库的订单语句,请自己填写一下 string strOrderNO = Request.Form["out_trade_no"];//订单号 string strPrice = Request.Form["total_fee"];//金额 如果你申请了商家购物卷功能,在返回信息里面请不要做金额的判断,否则会校验通过不了。 } else if (Request.Form["trade_status"] == "TRADE_FINISHED" || Request.Form["trade_status"] == "TRADE_SUCCESS")// 判断支付状态_交易成功结束(文档中有枚举表可以参考) { //更新自己数据库的订单语句,请自己填写一下 string strOrderNO = Request.Form["out_trade_no"];//订单号 string strPrice = Request.Form["total_fee"];//金额 } else { //更新自己数据库的订单语句,请自己填写一下 } Response.Write( "success"); //返回给支付宝消息,成功,请不要改写这个success //success与fail及其他字符的区别在于,支付宝的服务器若遇到success时,则不再发送请求通知(即不再调用该页面,让该页面再次运行起来), //若不是success,则支付宝默认没有收到成功的信息,则会反复不停地调用该页面直到失效,有效调用时间是24小时以内。 //最好写TXT文件,以记录下是否异步返回记录。 ////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库) //string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt; //StreamWriter fs = new StreamWriter(Server.MapPath("Notify_DATA/" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default); //fs.Write(TOEXCELLR); //fs.Close(); } else { Response.Write("fail"); //最好写TXT文件,以记录下是否异步返回记录。 //写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库) string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt; StreamWriter fs = new StreamWriter(Server.MapPath("Notify_DATA/" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default); fs.Write(TOEXCELLR); fs.Close(); } } }Return.aspx.cs
using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Text; using System.Collections.Specialized; using System.IO; using Gateway; /// <summary> /// 创建该页面文件时,请留心该页面文件是可以对其进行美工处理的,原因在于支付完成以后,当前窗口会从支付宝的页面跳转回这个页面。 /// 该页面称作“返回页”,是同步被支付宝服务器所调用,可当作是支付完成后的提示信息页,如“您的某某某订单,多少金额已支付成功”。 /// </summary> public partial class Alipay_Return : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string alipayNotifyURL = "https://www.alipay.com/cooperate/gateway.do?service=notify_verify"; //string alipayNotifyURL = "http://notify.alipay.com/trade/notify_query.do?";//此路径是在上面链接地址无法起作用时替换使用。 string key = ""; //partner 的对应交易安全校验码(必须填写) string partner = ""; //partner合作伙伴id(必须填写) string _input_charset = "utf-8";//编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。 alipayNotifyURL = alipayNotifyURL + "&partner=" + partner + "¬ify_id=" + Request.QueryString["notify_id"]; //获取支付宝ATN返回结果,true是正确的订单信息,false 是无效的 string responseTxt = AliPay.Get_Http(alipayNotifyURL, 120000); //*******加密签名程序开始//******* int i; NameValueCollection coll; //Load Form variables into NameValueCollection variable. coll = Request.QueryString; // Get names of all forms into a string array. String[] requestarr = coll.AllKeys; //进行排序; string[] Sortedstr = AliPay.BubbleSort(requestarr); //构造待md5摘要字符串 ; StringBuilder prestr = new StringBuilder(); for (i = 0; i < Sortedstr.Length; i++) { if (Request.Form[Sortedstr[i]] != "" && Sortedstr[i] != "sign" && Sortedstr[i] != "sign_type") { if (i == Sortedstr.Length - 1) { prestr.Append(Sortedstr[i] + "=" + Request.QueryString[Sortedstr[i]]); } else { prestr.Append(Sortedstr[i] + "=" + Request.QueryString[Sortedstr[i]] + "&"); } } } prestr.Append(key); //生成Md5摘要; string mysign = AliPay.GetMD5(prestr.ToString(), _input_charset); //*******加密签名程序结束******* string sign = Request.QueryString["sign"]; // Response.Write(prestr.ToString()); //调试用,支付宝服务器返回时的完整路径。 if (mysign == sign && responseTxt == "true") //验证支付发过来的消息,签名是否正确 { //更新自己数据库的订单语句,请自己填写一下 string strOrderNO = Request.QueryString["out_trade_no"];//订单号 string strPrice = Request.QueryString["total_fee"];//金额 string strTradeStatus = Request.QueryString["TRADE_STATUS"];//订单状态 Response.Write( "订单号:" + strOrderNO + "<br>金额:" + strPrice); //成功,可美化该页面,提示信息 } else { Response.Write("------------------------------------------"); Response.Write("<br>Result:responseTxt=" + responseTxt); Response.Write("<br>Result:mysign=" + mysign); Response.Write("<br>Result:sign=" + sign); Response.Write("支付失败"); //支付失败,提示信息 } } }
using System.Web; using System.Text; using System.Security.Cryptography; using System.IO; using System.Net; using System; /// <summary> /// New Interface for AliPay /// </summary> namespace Gateway { public class AliPay { /// <summary> /// 与ASP兼容的MD5加密算法 /// </summary> public static string GetMD5(string s, string _input_charset) { MD5 md5 = new MD5CryptoServiceProvider(); byte[] t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(s)); StringBuilder sb = new StringBuilder(32); for (int i = 0; i < t.Length; i++) { sb.Append(t[i].ToString("x").PadLeft(2, '0')); } return sb.ToString(); } /// <summary> /// 冒泡排序法 /// 按照字母序列从a到z的顺序排列 /// </summary> public static string[] BubbleSort(string[] r) { int i, j; //交换标志 string temp; bool exchange; for (i = 0; i < r.Length; i++) //最多做R.Length-1趟排序 { exchange = false; //本趟排序开始前,交换标志应为假 for (j = r.Length - 2; j >= i; j--) {//交换条件 if (System.String.CompareOrdinal(r[j + 1], r[j]) < 0) { temp = r[j + 1]; r[j + 1] = r[j]; r[j] = temp; exchange = true; //发生了交换,故将交换标志置为真 } } if (!exchange) //本趟排序未发生交换,提前终止算法 { break; } } return r; } /// <summary> /// 生成URL链接或加密结果 /// </summary> /// <param name="para">参数加密数组</param> /// <param name="_input_charset">编码格式</param> /// <param name="sign_type">加密类型</param> /// <param name="key">安全校验码</param> /// <returns>字符串URL或加密结果</returns> public static string CreatUrl( //string gateway,//GET方式传递参数时请去掉注释 string[] para, string _input_charset, string sign_type, string key ) { int i; //进行排序; string[] Sortedstr = BubbleSort(para); //构造待md5摘要字符串 ; StringBuilder prestr = new StringBuilder(); for (i = 0; i < Sortedstr.Length; i++) { if (i == Sortedstr.Length - 1) { prestr.Append(Sortedstr[i]); } else { prestr.Append(Sortedstr[i] + "&"); } } prestr.Append(key); //生成Md5摘要; string sign = GetMD5(prestr.ToString(), _input_charset); //以下是POST方式传递参数 return sign; //以下是GET方式传递参数 //构造支付Url; // char[] delimiterChars = { '='}; // StringBuilder parameter = new StringBuilder(); // parameter.Append(gateway); // for (i = 0; i < Sortedstr.Length; i++) // {//UTF-8格式的编码转换 // parameter.Append(Sortedstr[i].Split(delimiterChars)[0] + "=" + HttpUtility.UrlEncode(Sortedstr[i].Split(delimiterChars)[1]) + "&"); // } // // parameter.Append("sign=" + sign + "&sign_type=" + sign_type); // // //返回支付Url; // return parameter.ToString(); } //获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求 public static string Get_Http(string a_strUrl, int timeout) { string strResult; try { HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(a_strUrl); myReq.Timeout = timeout; HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse(); Stream myStream = HttpWResp.GetResponseStream(); StreamReader sr = new StreamReader(myStream, Encoding.Default); StringBuilder strBuilder = new StringBuilder(); while (-1 != sr.Peek()) { strBuilder.Append(sr.ReadLine()); } strResult = strBuilder.ToString(); } catch (Exception exp) { strResult = "错误:" + exp.Message; } return strResult; } } }위의 세 파일이 생성된 후 Alipay 결제 기능을 완료하는 데 필요한 곳에서 Alipay 인터페이스를 호출할 수 있습니다( Default.aspx.cs).
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using Gateway; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void BtnAlipay_Click(object sender, EventArgs e) { //业务参数赋值; string gateway = "https://www.alipay.com/cooperate/gateway.do?"; //支付接口 string service = "create_direct_pay_by_user"; //服务名称,这个是识别是何接口实现何功能的标识,请勿修改 string seller_email = ""; //商家签约时的支付宝帐号,即收款的支付宝帐号 string sign_type = "MD5"; //加密类型,签名方式“不用改” string key = ""; //安全校验码,与partner是一组,获取方式是:用签约时支付宝帐号登陆支付宝网站www.alipay.com,在商家服务我的商家里即可查到。 string partner = ""; //商户ID,合作身份者ID,合作伙伴ID string _input_charset = "utf-8"; //编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。 string show_url = "http://www.alipay.com/"; //展示地址,即在支付页面时,商品名称旁边的“详情”的链接地址。 string out_trade_no = TxtOrderno.Text.Trim(); //客户自己的订单号,订单号必须在自身订单系统中保持唯一性 string subject = TxtSubject.Text.Trim(); //商品名称,也可称为订单名称,该接口并不是单一的只能买一样东西,可把一次支付当作一次下订单 string body = TxtBody.Text.Trim(); //商品描述,即备注 string total_fee = TxtTotal_fee.Text.Trim(); //商品价格,也可称为订单的总金额 //服务器通知url(Alipay_Notify.aspx文件所在路经),必须是完整的路径地址 string notify_url = "http://localhost:8978/direct_vs2005_utf/Alipay_Notify.aspx"; //服务器返回url(Alipay_Return.aspx文件所在路经),必须是完整的路径地址 string return_url = "http://localhost:8978/direct_vs2005_utf/Alipay_Return.aspx"; //构造数组; //以下数组即是参与加密的参数,若参数的值不允许为空,若该参数为空,则不要成为该数组的元素 string[] para ={ "service="+service, "partner=" + partner, "seller_email=" + seller_email, "out_trade_no=" + out_trade_no, "subject=" + subject, "body=" + body, "total_fee=" + total_fee, "show_url=" + show_url, "payment_type=1", "notify_url=" + notify_url, "return_url=" + return_url, "_input_charset="+_input_charset }; //支付URL生成 string aliay_url = AliPay.CreatUrl( //gateway,//GET方式传递参数时请去掉注释 para, _input_charset, sign_type, key ); //以下是GET方式传递参数 //Response.Redirect(aliay_url); //以下是POST方式传递参数 Response.Write("<form name='alipaysubmit' method='post' action='https://www.alipay.com/cooperate/gateway.do?_input_charset=utf-8'>"); Response.Write("<input type='hidden' name='service' value=" + service + ">"); Response.Write("<input type='hidden' name='partner' value=" + partner + ">"); Response.Write("<input type='hidden' name='seller_email' value=" + seller_email + ">"); Response.Write("<input type='hidden' name='out_trade_no' value=" + out_trade_no + ">"); Response.Write("<input type='hidden' name='subject' value=" + subject + ">"); Response.Write("<input type='hidden' name='body' value=" + body + ">"); Response.Write("<input type='hidden' name='total_fee' value=" + total_fee + ">"); Response.Write("<input type='hidden' name='show_url' value=" + show_url + ">"); Response.Write("<input type='hidden' name='return_url' value=" + return_url + ">"); Response.Write("<input type='hidden' name='notify_url' value=" + notify_url + ">"); Response.Write("<input type='hidden' name='payment_type' value=1>"); Response.Write("<input type='hidden' name='sign' value=" + aliay_url + ">"); Response.Write("<input type='hidden' name='sign_type' value=" + sign_type + ">"); Response.Write("</form>"); Response.Write("<script>"); Response.Write("document.alipaysubmit.submit()"); Response.Write("</script>"); } }