1、 网站转接支付宝解决方案 大型网上购物系统除了能让会员选择货到付款结账方式外, 还应该提供一些更方便快捷的网上支付方式。如果网上商店没有足够的实力提供会员直接在网站中建立现金账户的功能, 就能够将订单信息转接到支付宝, 让会员从支付宝付款。当然就算会员能够在网站上建立自己的现金账户, 提供支付宝支付功能也不失为另一种方便快捷的支付方式, 这能够给客户提供更多可选的支付方式。 首先, 网上购物系统必须与支付宝公司签订合作协议, 以确保从本购物网站上传到 支付宝网站上的订单信息能被正确接收。 当会员于购物网站上买下一系列商品并选择支付宝付款方式后, 购
2、物系统即将会员购物的订单信息转发到支付宝, 网站页面也会转到支付宝的付款页面。此时, 支付宝页面会发送一个验证信息到本网站以确认支付宝正确收到订单信息。 会员于支付宝网站付款完成后, 网站页面会重新跳回本购物网站, 同时支付宝会将已付款的订单信息发回本网站以便对本购物网站的数据库进行必要的修改操作。另外本网站还需要向支付宝网站发送一个返回信息, 告知支付宝本系统已正确收到付款完毕的订单信息而且已经完成对数据的处理操作。 向支付宝网站传送订单信息时主要参数的含义: gateway : 支付接口 service: 识别是何接口实现何功能的表示 seller_email: 商家签约时的
3、支付宝账号, 即收款的支付宝账号 key: 安全校验码, 与partner是一组 partner: 商户ID, 合作伙伴ID sign_type: 加密类型 _input_charset: 编码类型 show_url: 展示地址, 即在支付宝页面时商品名称旁边的”详情”的链接地址 out_trade_no: 会员订单编号, 订单编号必须在本系统中保持唯一 subject: 商品名称, 也可称为订单名称, 该接口并不是单一的只能买一样东西, 可把一次支付当作一次下订单 body: 商品描述, 即备注 total_fee: 商品价格, 也可称为订单的总金额 源码
4、分析(C#): 首先必须建立一个通知页面( Notify.aspx) 和一个返回页面( Return.aspx) 以接受并验证从支付宝返回的信息并对数据库中相应的订单信息做修改处理操作。 Notify.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.Web
5、Controls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Collections.Specialized;
using System.IO;
using Gateway;
///
6、页面, 因此请做好自身网站订单信息与支付宝上的订单的同步工作 /// public partial class Alipay_Notify : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string alipayNotifyURL = ""; //string alipayNotifyURL = "";//此路径是在上面链接地址无法起作用时替换使用。 string partner =
7、""; //partner合作伙伴id( 必须填写) string key = ""; //partner 的对应交易安全校验码( 必须填写) string _input_charset = "utf-8";//编码类型, 完全根据客户自身的项目的编码格式而定, 千万不要填错。否则极其容易造成MD5加密错误。 alipayNotifyURL = alipayNotifyURL + "&partner=" + partner + "¬ify_id=" + Request.Form["notify_id"];
8、 //获取支付宝ATN返回结果, true是正确的订单信息, false 是无效的 string responseTxt = AliPay.Get_Http(alipayNotifyURL, 1 0); //*******加密签名程序开始******* int i; NameValueCollection coll; //Load Form variables into NameValueCollection variable. coll = Request.Form
9、 // 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 < Sort
10、edstr.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
11、]]); } else { prestr.Append(Sortedstr[i] + "=" + Request.Form[Sortedstr[i]] + "&"); } } } prestr.Append(key); string mysign = AliPay.GetMD5(prestr.ToString(), _input
12、charset); //*******加密签名程序结束******* string sign = Request.Form["sign"]; if (mysign == sign && responseTxt == "true") //验证支付发过来的消息, 签名是否正确, 只要成功进如这个判断里, 则表示该页面已被支付宝服务器成功调用 //但判断内出现自身编写的程序相关错误导致通知给支付宝并不是发送success的消息或没有更新客户自身的数据库的情况, 请自身程序编写好应对措施, 否则查明原因时困难之极
13、 { if (Request.Form["trade_status"] == "WAIT_BUYER_PAY")// 判断支付状态_等待买家付款( 文档中有枚举表能够参考) { //更新自己数据库的订单语句, 请自己填写一下 string strOrderNO = Request.Form["out_trade_no"];//订单号 string strPrice = Request.Form["t
14、otal_fee"];//金额 如果你申请了商家购物卷功能, 在返回信息里面请不要做金额的判断, 否则会校验经过不了。 } else if (Request.Form["trade_status"] == "TRADE_FINISHED" || Request.Form["trade_status"] == "TRADE_SUCCESS")// 判断支付状态_交易成功结束( 文档中有枚举表能够参考) { //更新自己数据库的订单语句, 请自己填写一下
15、 string strOrderNO = Request.Form["out_trade_no"];//订单号 string strPrice = Request.Form["total_fee"];//金额 } else { //更新自己数据库的订单语句, 请自己填写一下 } Response.Write("success"); //返回给支
16、付宝消息, 成功, 请不要改写这个success //success与fail及其它字符的区别在于, 支付宝的服务器若遇到success时, 则不再发送请求通知( 即不再调用该页面, 让该页面再次运行起来) , //若不是success, 则支付宝默认没有收到成功的信息, 则会重复不停地调用该页面直到失效, 有效调用时间是24小时以内。 //最好写TXT文件, 以记录下是否异步返回记录。 ////写文本, 纪录支付宝返回消息, 比对md5计算结果( 如网站不支持写txt文件, 可改
17、成写数据库) //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);
18、 //fs.Write(TOEXCELLR); //fs.Close(); } else { Response.Write("fail"); //最好写TXT文件, 以记录下是否异步返回记录。 //写文本, 纪录支付宝返回消息, 比对md5计算结果( 如网站不支持写txt文件, 可改成写数据库) string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign
19、" + 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
20、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 Syst
21、em.Text;
using System.Collections.Specialized;
using System.IO;
using Gateway;
///
22、m.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string alipayNotifyURL = ""; //string alipayNotifyURL = "";//此路径是在上面链接地址无法起作用时替换使用。 string key = ""; //partner 的对应交易安全校验码( 必须填写) string partner = ""; //partner合作伙伴id( 必须填写)
23、 string _input_charset = "utf-8";//编码类型, 完全根据客户自身的项目的编码格式而定, 千万不要填错。否则极其容易造成MD5加密错误。 alipayNotifyURL = alipayNotifyURL + "&partner=" + partner + "¬ify_id=" + Request.QueryString["notify_id"]; //获取支付宝ATN返回结果, true是正确的订单信息, false 是无效的 string responseTxt = Ali
24、Pay.Get_Http(alipayNotifyURL, 1 0); //*******加密签名程序开始//******* int i; NameValueCollection coll; //Load Form variables into NameValueCollection variable. coll = Request.QueryString; // Get names of all forms into a string array. Strin
25、g[] 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]]
26、 "" && Sortedstr[i] != "sign" && Sortedstr[i] != "sign_type") { if (i == Sortedstr.Length - 1) { prestr.Append(Sortedstr[i] + "=" + Request.QueryString[Sortedstr[i]]); } else {
27、 prestr.Append(Sortedstr[i] + "=" + Request.QueryString[Sortedstr[i]] + "&"); } } } prestr.Append(key); //生成Md5摘要; string mysign = AliPay.GetMD5(prestr.ToString(), _input_charset); //*******加密签名程序结束**
28、 string sign = Request.QueryString["sign"]; // Response.Write(prestr.ToString()); //调试用, 支付宝服务器返回时的完整路径。 if (mysign == sign && responseTxt == "true") //验证支付发过来的消息, 签名是否正确 { //更新自己数据库的订单语句, 请自己填写一下 string strOrderNO = Requ
29、est.QueryString["out_trade_no"];//订单号
string strPrice = Request.QueryString["total_fee"];//金额
string strTradeStatus = Request.QueryString["TRADE_STATUS"];//订单状态
Response.Write("订单号: " + strOrderNO + "
金额: " + strPrice); //成功, 可美化该页面, 提示信息
30、}
else
{
Response.Write("------------------------------------------");
Response.Write("
Result:responseTxt=" + responseTxt);
Response.Write("
Result:mysign=" + mysign);
Response.Write("
Result:sign=" + sign);
31、 Response.Write("支付失败"); //支付失败, 提示信息 } } } 除此之外在Notify.aspx页面和Return.aspx页面公用的一些方法, 能够提取出来放在一个公共的类里面( Alipay.cs) Alipay.cs 代码 using System.Web; using System.Text; using System.Security.Cryptography; using System.IO; using Sy
32、stem.Net;
using System;
///
33、 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].ToStri
34、ng("x").PadLeft(2, '0'));
}
return sb.ToString();
}
///
35、 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.CompareOr
36、dinal(r[j + 1], r[j]) < 0) { temp = r[j + 1]; r[j + 1] = r[j]; r[j] = temp; exchange = true; //发生了交换, 故将交换标志置为真 } } if
37、exchange) //本趟排序未发生交换, 提前终止算法
{
break;
}
}
return r;
}
///
39、input_charset, string sign_type, string key ) { int i; //进行排序; string[] Sortedstr = BubbleSort(para); //构造待md5摘要字符串 ; StringBuilder prestr = new StringBuilder();
40、 for (i = 0; i < Sortedstr.Length; i++) { if (i == Sortedstr.Length - 1) { prestr.Append(Sortedstr[i]); } else { prestr.Append(Sortedstr[i] + "&")
41、 } } prestr.Append(key); //生成Md5摘要; string sign = GetMD5(prestr.ToString(), _input_charset); //以下是POST方式传递参数 return sign; //以下是GET方式传递参数 //构造支付Url; // cha
42、r[] delimiterChars = { '='}; // StringBuilder parameter = new StringBuilder(); // parameter.Append(gateway); // for (i = 0; i < Sortedstr.Length; i++) // {//UTF-8格式的编码转换 // parameter.Append(Sortedstr[i].Split(delimiterChars)[0] + "=" +
43、HttpUtility.UrlEncode(Sortedstr[i].Split(delimiterChars)[1]) + "&"); // } // // parameter.Append("sign=" + sign + "&sign_type=" + sign_type); // // //返回支付Url; // return parameter.ToString(); } //获取远程服务器ATN结果, 验证是否是支付宝服务器发来的请求
44、 public static string Get_Http(string a_strUrl, int timeout) { string strResult; try { HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(a_strUrl); myReq.Timeout = timeout; HttpWebRespo
45、nse HttpWResp = (HttpWebResponse)myReq.GetResponse(); Stream myStream = HttpWResp.GetResponseStream(); StreamReader sr = new StreamReader(myStream, Encoding.Default); StringBuilder strBuilder = new StringBuilder(); while (-1 != sr.P
46、eek()) { strBuilder.Append(sr.ReadLine()); } strResult = strBuilder.ToString(); } catch (Exception exp) { strResult = "错误: " + exp.Message; }
47、 return strResult; } } } 以上三个文件建之后, 就能够在需要的地方对支付宝接口进行调用以完成支付宝支付的功能了( 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.We
48、b.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) { //业务参数赋值;
49、 string gateway = ""; //支付接口 string service = "create_direct_pay_by_user"; //服务名称, 这个是识别是何接口实现何功能的标识, 请勿修改 string seller_email = ""; //商家签约时的支付宝帐号, 即收款的支付宝帐号 string sign_type = "MD5";
50、 //加密类型,签名方式”不用改” string key = ""; //安全校验码, 与partner是一组, 获取方式是: 用签约时支付宝帐号登陆支付宝网站.com, 在商家服务我的商家里即可查到。 string partner = ""; //商户ID, 合作身份者ID, 合作伙伴ID string _input_charset = "utf-8";






