Stripe支付介紹在asp.net mvc中(zhong)開發(fa)對接(jie),圖文加(jia)代(dai)碼(ma)說明
最近(jin)一個國(guo)外的電商項目,需要對(dui)接支(zhi)付(fu)(fu)功能,國(guo)內的支(zhi)付(fu)(fu)一般(ban)使(shi)用微信支(zhi)付(fu)(fu)、支(zhi)付(fu)(fu)寶、銀聯等(deng)等(deng),但國(guo)際上(shang)一般(ban)使(shi)用Paypal、Skrill、BrainTree、Stripe等(deng),經(jing)過內部綜合考量(liang)所以最后選擇使(shi)用 Stripe支(zhi)付(fu)(fu)。
Stripe的對(dui)接(jie)相(xiang)對(dui)還是比較簡單(dan)的,只是相(xiang)關(guan)的文檔(dang)是英(ying)文的,且(qie)國(guo)內和國(guo)外的思想不(bu)一(yi)樣,看(kan)文檔(dang)不(bu)是很方便。
做(zuo)為技術人員這里我(wo)將(jiang)對接中所(suo)遇到(dao)的問題和解決(jue)方(fang)法匯總,希望能(neng)對開發人員有所(suo)幫助。
一:Stripe支付介紹
Stripe支付國際(ji)支付還是非(fei)常有(you)名氣(qi)的,具體的介紹下(xia)面的一些說明:
- 中文官網:
- Stripe國際支付簡介:
- Stripe支付對接還是非常方便的。
- Stripe支付功能也還是很強大的包括支付、賬單、訂閱等等。
二:Stripe技術對接
- 對接前的準備工作
- 需要去官網申請一個賬號,好像是國內的銀行卡不好申請。具體如何申請還請百度搜索下,我這里就不贅述了。
- 申請好以后在后臺拿到測試的公鑰和私鑰。
- 需要申請HTTPS證書,這個異步通知的接口需要提供HTTPS的域名。
- 官網接口文檔,共區分后端、前端、ios和安卓。
- 后端的接口:
- 前端的接口:
- 其它的一些使用文檔:
- 支付對接方式說明:共有2中方式。
- 方式一:使用Stripe的支付頁面進行支付(官方名稱:CheckOut)。
- 這種分2種情況:
- 跳轉到Stripe的支付頁面進行支付,這種類似于支付寶的對接,需要跳轉到支付寶的支付頁面。Stripe的支付頁面效果圖如下。
![]()
- 自己的頁面構建一個Stripe的支付,這種類似于微信公眾號的支付。
- 這種分2種情況:
- 方式二:自己做支付頁面,通過接口的方式進行支付。
- 官網給出了很多HTML示例效果,可下載后自己修改下。
- 采用這種方式,輸入信用卡等信息是Stripe通過js控制的,我們是拿不到用戶輸入的相關信息的,為了安全。
- 不管是使用方式一和方式二,我們都無法獲取用戶輸入的信用卡等信息。
- 推薦使用方式一對接,有以下幾點:
- 用戶在Stripe輸入銀行卡信息,用戶感覺要更加安全。
- 減少不必要的開發工作,因為自己做的收銀頁面沒法和Stripe的比較。
- 方式一:使用Stripe的支付頁面進行支付(官方名稱:CheckOut)。
- 下面所有的流程主要是使用跳轉到Stripe支付頁面支付。
- 簡單的流程說明
- 用戶點擊頁面上的“支付”按鈕。
- 通過js調用后臺的接口,接口中要調用Stripe的接口創建支付的會話(Session),調用Stripe接口之前需要設置一些數據,包括支付金額、支付方式等等,這個后面說明。調用接口成功則Stripe會返回一個SessionId,將該值返會給前端。
- 前端拿到SessionId以后,帶上改參數跳轉到Stripe的支付頁面。
- 用戶如果取消支付或支付成功,則跳轉到創建Session配置的取消地址和支付成功跳轉地址。
- 支付成功或其他的一些事件,Stripe會異步通知我們支付結果。
- 上面這幾步驟是大致的流程,還請有多的細節問題。
- 下面我們根據上面簡單的流程進行一步步詳細的說明。
- 下面的演示代碼是:.NET MVC
三:發起支付
- 官網有個快速開始支付的說明文檔,
- 做一個HTML頁面,頁面上需要引用Stripe的js文件和點擊跳轉到支付按鈕。當然支付的頁面上還有很多其他的一些東西,比如收貨地址、商品信息等等。
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<meta charset="utf-8" />
-
<title></title>
-
<script src="~/js/jquery-1.12.4.min.js"></script>
-
<script src="//js.stripe.com/v3/"></script>
-
-
</head>
-
<body>
-
-
<button id="checkout-button">去付款</button>
-
-
<script type="text/javascript">
-
-
//創建(jian)一個stripe,里面的(de)參數則是stripe申請的(de)公鑰,在后臺(tai)能(neng)查看到,pk_開通的(de),加test表示是測試的(de)
-
var stripe = Stripe('pk_test_xxx'); //輸入自己(ji)的(de)pk_test
-
var checkoutButton = document.getElementById('checkout-button');
-
-
//支付(fu)按鈕點擊事件
-
checkoutButton.addEventListener('click', function () {
-
-
//調用后端(duan)的(de)接口
-
fetch('/home/CreateCheckoutSession', {
-
method: 'POST',
-
})
-
.then(function (response) {
-
return response.json();
-
})
-
.then(function (session) {
-
//調用后端接口成功,得到sessionId,頁面會在(zai)函數里面進行(xing)跳轉
-
return stripe.redirectToCheckout({ sessionId: session.id });
-
})
-
.then(function (result) {
-
-
if (result.error) {
-
alert(result.error.message);
-
}
-
})
-
.catch(function (error) {
-
console.error('Error:', error);
-
});
-
});
-
</script>
-
-
-
-
</body>
-
-
</html>
-
- 上面的頁面中需要一個后臺調用Stripe來產生SessionId。
- 后端代碼,VS上先在NuGet上引用第三方的包,名稱:Stripe.net。
- 后端提供SessionId的代碼如下
-
/// <summary>
-
/// 調用stripe創建支付(fu)的會(hui)話(hua),成(cheng)功則返回會(hui)話(hua)的Id,用于頁面跳轉(zhuan)
-
/// </summary>
-
/// <returns></returns>
-
[
-
public ActionResult CreateCheckoutSession()
-
{
-
try
-
{
-
// Stripe的私鑰,在(zai) Stripe后臺能看到 sk開頭的,_test則(ze)表示是用于測試環境的。
-
StripeConfiguration.ApiKey = "sk_test_xx"; //sk_test_xxx 這里需要修改
-
-
//封裝支付請求的數據,
-
//字段(duan)說明詳見(jian)官(guan)網://stripe.com/docs/api/checkout/sessions/object
-
var options = new SessionCreateOptions
-
{
-
PaymentMethodTypes = new List<string>
-
{
-
"card" ,"alipay" //支持(chi)的付款方式
-
},
-
BillingAddressCollection= "required",//是否要收集(ji)帳單地址(zhi)信息
-
-
LineItems = new List<SessionLineItemOptions>
-
{
-
new SessionLineItemOptions
-
{
-
PriceData = new SessionLineItemPriceDataOptions
-
{
-
UnitAmount = 2000, //需要支付的金額(e)
-
Currency = "usd",//支持(chi)的貨幣簡寫,具體見官網
-
ProductData = new SessionLineItemPriceDataProductDataOptions
-
{
-
Name = "支付(fu)的顯(xian)示名稱(cheng)(cheng),或(huo)者(zhe)是商品名稱(cheng)(cheng)",
-
Images= new List<string>(){"//www.angelasp.com/images/angellogo.gif" },
-
Description="支付的描述信(xin)息(xi),可以是商品的描述等信(xin)息(xi)"
-
},
-
},
-
Quantity = 1,
-
},
-
},
-
-
Mode = "payment",
-
SuccessUrl = "//example.com/success", //支付(fu)成功以后跳轉的(de)URL地(di)址
-
CancelUrl = "//example.com/cancel",//用戶取(qu)消支(zhi)付以(yi)后跳轉的URL地址
-
};
-
-
options.PaymentIntentData = new SessionPaymentIntentDataOptions();
-
options.PaymentIntentData.Metadata = new Dictionary<string, string>
-
{
-
{ "sn", "6735" }, { "attachmentValue", "6735" }, //傳遞的(de)自定義參(can)數,回(hui)調通知的(de)時候會原樣返回(hui)
-
};
-
-
var service = new SessionService();
-
Session session = service.Create(options);
-
-
return Json(new { id = session.Id });
-
}
-
catch (Exception ex)
-
{
-
throw ex;
-
}
-
}
-
- 上面前端HTML和后端的接口都處理好以后,點擊頁面上的那個去付款的按鈕,則會跳轉到Stripe的收銀臺頁面(下圖)。
![]()
- Stripe的測試也非常方便,官方提供了很多測試的卡號,下面表格是我收集整理的一些。
-
卡號
品牌
CVC
年月
4242424242424242
Visa
任意3位數字
大于當前時間的年月
4000056655665556
Visa (debit)
任意3位數字
大于當前時間的年月
5555555555554444
Mastercard
任意3位數字
大于當前時間的年月
2223003122003222
Mastercard (2-series)
任意3位數字
大于當前時間的年月
5200828282828210
Mastercard (debit)
任意3位數字
大于當前時間的年月
5105105105105100
Mastercard (prepaid)
任意3位數字
大于當前時間的年月
378282246310005
American Express
任意4位數字
大于當前時間的年月
371449635398431
American Express
任意4位數字
大于當前時間的年月
6011111111111117
Discover
任意3位數字
大于當前時間的年月
6011000990139424
Discover
任意3位數字
大于當前時間的年月
3056930009020004
Diners Club
任意3位數字
大于當前時間的年月
36227206271667
Diners Club (14 digit card)
任意3位數字
大于當前時間的年月
3566002020360505
JCB
任意3位數字
大于當前時間的年月
6200000000000005
UnionPay
任意3位數字
大于當前時間的年月
信用卡(ka)的年月,填寫大(da)于當前時間(jian)的年月即(ji)可。
![]()
- 在Stripe的支付頁面填寫好相關信息以后點擊支付,如果沒有問題的話就會支付成功。
- 支付成功以后可在Stripe的后臺看到付款的金額和一些日志,日志包括事件、接口請求日志、訂單數據等等。因為是測試的數據所以要先開啟可查看測試數據,不然是看不到的,如何開啟看下圖。
![]()
- 完成上面的步驟以后,則發起支付收款簡單的流程沒有問題下,下面說下如何接受Stripe異步通知。
四:接受異步通知
- Stripe支持很多事件的通知,例如Session創建完成、訂單付款完成、退款等等,詳見官網說明。
- 需要一個HTTPS的接口,如果沒有證書可去阿里云等申請免費的證書。
- 在Stripe后臺添加一個端點(接受通知的配置)見下圖
![]()
- 事件類型非常多,目前我們是做跳轉支付,支付成功了通知我們,則選擇:payment_intent.succeeded 事件
- 拿到驗證端點的密鑰,每個端點有獨立的密鑰,見下圖
![]()
- 編寫接受通知的接口代碼,,下面我把代碼整理了貼出來。
-
/// <summary>
-
-
/// 支付成功(gong)的異步通(tong)知接口(kou)
-
-
/// </summary>
-
-
/// <returns></returns>
-
-
[
-
-
public ActionResult Notify()
-
-
{
-
-
var json = new StreamReader(HttpContext.Request.InputStream).ReadToEndAsync().Result;
-
-
try
-
-
{
-
-
//驗證數據(ju)的來源
-
-
string endpointSecret = "whsec_XXXXX";//后(hou)臺創建的端點簽(qian)名密(mi)鑰
-
-
var stripeEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], endpointSecret);
-
-
-
-
//stripeEvent.Type 則是不同的事件,具體則看你配置端點的時(shi)候,這個接口(kou)設置了那些事件
-
-
if (stripeEvent.Type == Events.PaymentIntentSucceeded)
-
-
{
-
-
//支付(fu)成(cheng)功的業(ye)務(wu)處(chu)理
-
-
var payModel = stripeEvent.Data.Object as PaymentIntent;
-
-
-
-
decimal payAmount = payModel.Amount / 100M; //支付的金額
-
-
string payPaySN = payModel.Id;//支付方的(de)唯一訂單號
-
-
string payCurrency = payModel.Currency;//支付的貨(huo)幣
-
-
-
-
//賬(zhang)單信息,如果(guo)創建Session的時候設置收(shou)集賬(zhang)單信息,則這里可(ke)以(yi)獲取(qu)到
-
-
var billing = payModel.Charges.Data[0].BillingDetails;
-
-
string billingName = billing.Name;
-
-
string billingEmail = billing.Email;
-
-
string billingPhone = billing.Phone;
-
-
string billingCity = billing.Address.City;
-
-
string billingCountry = billing.Address.Country;
-
-
string billingLine1 = billing.Address.Line1;
-
-
string billingLine2 = billing.Address.Line2;
-
-
string billingPostalCode = billing.Address.PostalCode;
-
-
string billingState = billing.Address.State;
-
-
-
-
//發起支付創建(jian)的自(zi)定義參數,這里(li)具(ju)體根據自(zi)己(ji)的業務來(lai)
-
-
string orderSN = payModel.Metadata["sn"];
-
-
string attachmentValue = payModel.Metadata["attachmentValue"];
-
-
-
-
//其它(ta)的一(yi)些(xie)業務(wu)處理,比如(ru)更(geng)新訂單狀態等等
-
-
-
-
-
-
}
-
-
else if (stripeEvent.Type == Events.PaymentMethodAttached)
-
-
{
-
-
var paymentMethod = stripeEvent.Data.Object as PaymentMethod;
-
-
Console.WriteLine("PaymentMethod was attached to a Customer!");
-
-
}
-
-
else
-
-
{
-
-
Console.WriteLine("Unhandled event type: {0}", stripeEvent.Type);
-
-
}
-
-
-
-
return Json(new { id = 1});
-
-
}
-
-
catch (StripeException)
-
-
{
-
return Json(new { id =2 });
-
-
}
-
-
}
-
- 完成上面的步驟,就可以測試發起支付了和接受支付結果了。
- Stripe后臺可以看到請求的日志記錄,可以針對端點發送測試數據,這些對于調試程序還是很方便的,具體如何使用我就不多說了,都有中文的大家用心看下就懂了。
- 上線的時候需要將相關配置參數換成正式環境的。
以上(shang)只是我(wo)在研究(jiu)Stripe支(zhi)付的一點簡單(dan)的總(zong)結,時間倉促很(hen)多細節還未深入詳細說明。以上(shang)如有不正之處(chu)還望見諒(liang),可給(gei)我(wo)留言(yan)討論,謝謝!




