大型網上購物系統除了能讓會員選擇貨到付款結帳方式外,還應該提供一些更方便快捷的網上支付方式。若是網上商店沒有足夠的實力提供會員直接在網站中創建現金帳戶的功能,就能夠將訂單信息轉接到支付寶,讓會員從支付寶付款。固然就算會員能夠在網站上創建本身的現金帳戶,提供支付寶支付功能也不失爲另外一種方便快捷的支付方式,這能夠給客戶提供更多可選的支付方式。算法
首先,網上購物系統必須與支付寶公司簽定合做協議,以確保從本購物網站上傳到數據庫
支付寶網站上的訂單信息能被正確接收。數組
當會員於購物網站上買下一系列商品並選擇支付寶付款方式後,購物系統即將會員購物的訂單信息轉發到支付寶,網站頁面也會轉到支付寶的付款頁面。此時,支付寶頁面會發送一個驗證信息到本網站以確認支付寶正確收到訂單信息。安全
會員於支付寶網站付款完成後,網站頁面會從新跳回本購物網站,同時支付寶會將已付款的訂單信息發回本網站以便對本購物網站的數據庫進行必要的修改操做。另外本網站還須要向支付寶網站發送一個返回信息,告知支付寶本系統已正確收到付款完畢的訂單信息而且已經完成對數據的處理操做。服務器
向支付寶網站傳送訂單信息時主要參數的含義:異步
gateway :支付接口ide
service:識別是何接口實現何功能的表示oop
seller_email:商家簽約時的支付寶帳號,即收款的支付寶帳號源碼分析
key:安全校驗碼,與partner是一組post
partner:商戶ID,合做夥伴ID
sign_type:加密類型
_input_charset:編碼類型
show_url:展現地址,即在支付寶頁面時商品名稱旁邊的「詳情」的連接地址
out_trade_no:會員訂單編號,訂單編號必須在本系統中保持惟一
subject:商品名稱,也可稱爲訂單名稱,該接口並非單一的只能買同樣東西,可把一次支付看成一次下訂單
body:商品描述,即備註
total_fee:商品價格,也可稱爲訂單的總金額
源碼分析(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.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("支付失敗"); //支付失敗,提示信息 } } }
除此以外在Notify.aspx頁面和Return.aspx頁面公用的一些方法,能夠提取出來放在一個公共的類裏面(Alipay.cs)
Alipay.cs
代碼 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; } } }
以上三個文件建以後,就能夠在須要的地方對支付寶接口進行調用以完成支付寶支付的功能了(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>"); } }
轉接到支付寶的付款功能在調試過程當中,必須真實的從網站夠買商品並跳轉到支付寶網
付款。能夠將所買商品的單價設爲0.01元,從支付寶付款成功並從新跳回本網站後,檢查訂單信息是否正確,以及對傳回的數據所作的處理操做是否正確。總之,用支付寶付款的功能在調試過程當中必須進行實際的支付操做才能發現錯誤。