我正在按照 Stripe 的在线文档为连接的帐户创建嵌入式付款表单。
我的测试 API 密钥在
Program.cs
中设置正确。
我的控制器中的这个端点大部分直接来自 Stripe 的 API 指南,并且它很高兴地返回客户端密钥:
[HttpGet]
[AllowAnonymous]
public ContentResult StripeCheckoutSession()
{
var options = new Stripe.Checkout.SessionCreateOptions
{
LineItems = new List<Stripe.Checkout.SessionLineItemOptions>
{
new Stripe.Checkout.SessionLineItemOptions
{
PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions
{
Currency = "aud",
ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions
{
Name = "T-shirt",
},
UnitAmount = 1000,
},
Quantity = 1,
},
},
PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions
{
ApplicationFeeAmount = 123,
},
Mode = "payment",
UiMode = "embedded",
ReturnUrl = "abc={CHECKOUT_SESSION_ID}"
};
var requestOptions = new RequestOptions
{
StripeAccount = "acct_12345...";
};
var service = new SessionService();
Session session = service.Create(options, requestOptions);
return Content(JsonConvert.SerializeObject(session.ClientSecret));
}
在我的
.cshtml
视图的头部,我添加了这个脚本元素:
<script src="https://js.stripe.com/v3/"></script>
在正文中我有这个标记:
<div id="checkout">
</div>
还在头部我有从 Stripe 的 API 指南复制的 JavaScript。
<script type="text/javascript">
// initialize Stripe.js
const stripe = Stripe('pk_test_blah...', {
stripeAccount: {{CONNECTED_ACCOUNT_ID}},
});
initialize();
// fetch checkout session and retrieve client secret
async function initialize() {
const fetchClientSecret = async () => {
const response = await fetch("/StripeCheckoutSession", {
method: "POST",
});
const { clientSecret } = await response.json();
return clientSecret;
};
// initialize checkout
const checkout = await stripe.initEmbeddedCheckout({
fetchClientSecret,
});
// mount checkout
checkout.mount('#checkout');
}
</script>
注意,我已将
{{CONNECTED_ACCOUNT_ID}}
替换为对视图模型中实际值的引用,如下所示:
'@Model.StripeAccountID'
当我运行该项目时,没有任何反应 - 空白屏幕。我一半预料到了这一点,因为我不明白
initialize()
是如何被调用的。我发现它永远不会执行。
所以我写了js,我认为它应该如下工作:
<script type="text/javascript">
// initialize Stripe.js
const stripe = Stripe('pk_test_blah...', {
stripeAccount: '@Model.StripeAccountID',
});
$(document).ready(function () {
initialize();
})
// fetch checkout session and retrieve the client secret
async function initialize() {
try {
alert('Start');
const fetchClientSecret = async () => {
const response = await fetch("StripeCheckoutSession", {
method: "GET",
});
const { clientSecret } = await response.json();
return clientSecret;
};
// initialize checkout
alert('Init checkout');
const checkout = await stripe.initEmbeddedCheckout({
fetchClientSecret,
});
// mount checkout
alert('Finish mount');
checkout.mount('#checkout');
}
catch (err) {
alert(err);
}
}
</script>
我看到
alert('Start')
,然后看到 alert('Finish mount')
,但没有看到 alert('Init checkout')
。
我还尝试使用一个单独的函数,通过 AJAX 调用来获取客户端密钥。该功能本身有效,但初始化结帐失败。
我做错了什么?谁能帮我解决这个问题吗?
他们的示例使用index.js +index.html,其工作方式与 MVC/Razor 页面略有不同。一件事是异步处理有点关闭。考虑尝试而不是包装新的异步方法:
async function initialize() {
try {
alert('Start');
await fetch("StripeCheckoutSession", {
method: "GET",
headers: {
'Content-Type': 'application/json'
},
}).then (response => {
if (response.ok) {
return response.json();
} else { /* handle server exception */ }
)}.then (data => {
// initialize checkout
alert('Init checkout');
const checkout = await stripe.initEmbeddedCheckout({
data.clientSecret
});
// mount checkout
alert('Finish mount');
checkout.mount('#checkout');
});
catch (err) {
alert(err);
}
}
除此之外,启用浏览器调试工具并检查控制台中的错误,并考虑在 JS 中设置断点以验证是否按预期调用了内容。
我们首先要做的是打开浏览器控制台,看看初始化stripe.js时是否有错误
接下来,确保 @Model.StripeAccountID 解析为帐户 ID。您可以打印一些日志来确认这一点。我不熟悉 .net,但我找到了另一个page,它展示了如何将变量从 .net 传递到 javascript。
这是给您的工作示例,您可以先检查一下。在此示例代码中我使用的是 IActionResult,而不是 ContentResult。
@model Demo.StripeSettings
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Stripe Embedded Checkout</title>
<script src="https://js.stripe.com/v3/"></script>
</head>
<body>
<div id="checkout"></div>
<script type="text/javascript">
const stripe = Stripe('@Model.PublishableKey', {
stripeAccount: 'acct_1Q***XAU',
});
document.addEventListener("DOMContentLoaded", function () {
initialize();
});
async function initialize() {
try {
const response = await fetch('/Payment/CreateCheckoutSession', {
method: 'GET',
});
const data = await response.json();
const clientSecret = data.clientSecret;
const checkout = await stripe.initEmbeddedCheckout({
clientSecret: clientSecret,
});
checkout.mount('#checkout');
} catch (error) {
console.error('Error:', error);
}
}
</script>
</body>
</html>
控制器
using Demo.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Stripe.Checkout;
using Stripe;
using System.Diagnostics;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace Demo.Controllers
{
public class PaymentController : Controller
{
private readonly ILogger<PaymentController> _logger;
public PaymentController(ILogger<PaymentController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
var stripeSettings = new StripeSettings
{
PublishableKey = "pk_test_51QHc8D2LtiFaqkvHQ4VaoOG******NBOZuXO4WGqL00Mx3gYALt"
};
return View(stripeSettings);
}
[HttpGet]
[AllowAnonymous]
public IActionResult CreateCheckoutSession()
{
var options = new Stripe.Checkout.SessionCreateOptions
{
LineItems = new List<Stripe.Checkout.SessionLineItemOptions>
{
new Stripe.Checkout.SessionLineItemOptions
{
PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions
{
Currency = "aud",
ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions
{
Name = "T-shirt",
},
UnitAmount = 1000,
},
Quantity = 1,
},
},
PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions
{
ApplicationFeeAmount = 123,
},
Mode = "payment",
UiMode = "embedded",
ReturnUrl = "https://your-domain.com/return?session_id=cs_test_a1b2c3d4e5f6g7h8i9j0k"
};
var requestOptions = new RequestOptions
{
StripeAccount = "acct_1Q***XAU",
};
var service = new SessionService();
Session session = service.Create(options, requestOptions);
return Json(new { clientSecret = session.ClientSecret });
}
}
}
条纹设置
namespace Demo
{
public class StripeSettings
{
public string? SecretKey { get; set; }
public string? PublishableKey { get; set; }
}
}