近日網站需要對接國際化的支付接口PayPal,折騰了幾天把遇到的坑記錄下以備后用。
1.第一步先到官網申請商家賬戶https://www.paypal.com/這里的具體步驟我不太清楚,畢竟不是我來申請的
2.因為我們這里是網站用到的,使用了最便捷的網站付款標准版,其他的還可以用快速結賬的API來實現。
首先我們把需要用到的參數信息配置到config中
<!--paypal支付--> <add key="payPalBusiness" value="你的賬戶"/> <add key="payPalReturnUrl" value="操作完成后的返回地址"/> <add key="payPalNotifyUrl" value="操作完成后的異步通知頁面"/>
然后我們構建需要我們進行Post的頁面代碼,將必須填寫的值存放到隱藏域<input type="hidden" />之中
string webUrl = CFun.GetAppStr("webUrl"); string business = CFun.GetAppStr("payPalBusiness"); string returnUrl = CFun.GetAppStr("payPalReturnUrl"); string notifyUrl = CFun.GetAppStr("payPalNotifyUrl"); Dictionary<string, string> sParaTemp = new Dictionary<string, string>(); sParaTemp.Add("cmd", "_xclick"); //按鈕類型,包含:_xclick單個商品立即購買、_xclick_subscription訂閱、_cart購物車、s_x-click加密 sParaTemp.Add("business", business); //商戶名稱 sParaTemp.Add("item_name", product_name); //商品名稱 sParaTemp.Add("item_number", out_trade_no); //商品編號 sParaTemp.Add("currency_code", "USD"); //貨幣類型,默認美元 sParaTemp.Add("amount", payMoney.ToString()); //付款金額 sParaTemp.Add("notify_url", notifyUrl); //通知地址 sParaTemp.Add("cancel_return", webUrl); //取消返回地址 sParaTemp.Add("return", returnUrl); //返回地址 string submitHtml = PayPalSubmit.BuildRequest(sParaTemp, "post"); Response.Write(submitHtml);
/// <summary> /// 建立請求,以表單HTML形式構造(默認) /// </summary> /// <param name="sParaTemp">請求參數數組</param> /// <param name="strMethod">提交方式。兩個值可選:post、get</param> /// <param name="strButtonValue">確認按鈕顯示文字</param> /// <returns>提交表單HTML文本</returns> public static string BuildRequest(Dictionary<string, string> dicPara, string strMethod) {
//正式的是https://www.paypal.com/cgi-bin/webscr,這里我們用測試的地址進行測試
string actionUrl = "https://www.sandbox.paypal.com/cgi-bin/webscr"; StringBuilder sbHtml = new StringBuilder(); sbHtml.Append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"); sbHtml.Append("<form id='paypalsubmit' name='alipaysubmit' action='" + actionUrl + "' method='" + strMethod.ToLower().Trim() + "'>"); foreach (KeyValuePair<string, string> temp in dicPara) { sbHtml.Append("<input type='hidden' name='" + temp.Key + "' value='" + temp.Value + "'/>"); } //submit按鈕控件請不要含有name屬性 sbHtml.Append("<input type='submit' style='display:none;'></form>"); sbHtml.Append("<script>document.forms['paypalsubmit'].submit();</script>"); return sbHtml.ToString(); }
這幾個參數是比較重要的,更全面的參數介紹可以去官網查找相關文檔
3.發起代碼可以了,我們接下來寫一下返回和通知頁面的代碼
在通知頁面我們可以獲取到下面幾個關鍵參數
string item_number = CFun.RequestPamStr("item_number"); //商品編號 string pay_order = CFun.RequestPamStr("tx"); //paypal交易編號 string pay_status = CFun.RequestPamStr("st"); //交易狀態
我們可以通過item_number參數跟數據庫做數據對應,根據pay_order做驗證防止重復使用,根據pay_status判斷是否交易成功(pay_status="Completed")
這里有一點要注意,PayPal默認的是沒有自動返回的,需要進行相關配置。操作步驟:用戶信息-->銷售通知-->網站付款習慣設定
將圖中兩處設置為開啟即可。
4.返回頁面一般只是用來顯示充值結果,處理相關業務邏輯我們一般要放在通知頁面進行操作。
string response=ValidateSource(); if (response == "VERIFIED") //信息驗證成功 { string sendData = response; string item_number = CFun.RequestPamStr("item_number"); //商品編號 string pay_order = CFun.RequestPamStr("txn_id"); //paypal交易編號 string pay_status = CFun.RequestPamStr("payment_status"); //交易狀態 ErrorLog.sendLog(new Exception(),"商品編號:"+item_number+";交易編號:"+pay_order+"交易狀態:"+pay_status); if (pay_status == "Completed") //付款成功 { //業務處理 } Response.Write(sendData); }
/// <summary>
/// 驗證返回地址是否是官方返回
/// </summary>
/// <returns></returns>
private string ValidateSource()
{
//Post back to either sandbox or live
string strSandbox = "https://www.sandbox.paypal.com/cgi-bin/webscr";
string strLive = "https://www.paypal.com/cgi-bin/webscr";
//System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; //Framework4.5支持
ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072; //4.0寫法
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(strSandbox);
//Set values for the request back
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
byte[] param = Request.BinaryRead(HttpContext.Current.Request.ContentLength);
string strRequest = Encoding.ASCII.GetString(param);
string ipnPost = strRequest;
strRequest += "&cmd=_notify-validate";
req.ContentLength = strRequest.Length;
//for proxy
//WebProxy proxy = new WebProxy(new Uri("http://url:port#"));
//req.Proxy = proxy;
//Send the request to PayPal and get the response
StreamWriter streamOut = new StreamWriter(req.GetRequestStream(),
System.Text.Encoding.ASCII);
streamOut.Write(strRequest);
streamOut.Close();
StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream());
string strResponse = streamIn.ReadToEnd();
streamIn.Close();
return strResponse;
}
ValidateSource方法主要是通過將獲取到的參數+"&cmd=_notify-validate"后調用接口進行驗證,查看參數傳遞過程中是否被篡改,如果返回VERIFIED證明參數信息一致。
注意上面標紅的地方,這個一定不能少,我們訪問的https接口,如果少了上面的代碼會報異常:請求被中止: 未能創建 SSL/TLS 安全通道
好了,上面代碼寫完后我們就可以發布到服務器進行測試了,paypal的測試還是比較好的,給我們提供了專門的測試地址,可以任意添加商戶和個人賬戶來進行測試。
首先我們用我們注冊的賬戶來登錄:https://developer.paypal.com/
登錄后我們找到
這里會給我們默認兩個賬戶,當然你也可以做任意的修改,然后我們就可以用我們設定的賬戶進行測試了
測試完成以后如果我們想登錄我們的測試賬戶進行信息查看就需要用到這個網址:https://www.sandbox.paypal.com
我們這里用商戶賬號進行登錄,在這里我們同樣需要把步驟3上面的配置信息再次進行操作。
在這里我們還能查看我們的IPN信息