如何使用Stripe元素构建结账表单

491 阅读8分钟

使用Stripe元素构建结账表单

Stripe元素为开发人员提供了预先构建的UI组件,以便为他们的应用程序创建漂亮的结账流程。此外,Stripe元素在将你的应用程序改变成一个支付解决方案时也很好。

如果你已经准备好开始接受付款,并迅速上手,那么Stripe元素是最好的开始方式。Stripe元素是一种在优化转换中接受付款的方式,是您业务的一个重要组成部分。

结账表格是一个在线表格,您在其中放入您的卡或其他您想使用的支付手段的细节。你也可以在这个表格中放入你的名字和其他购买细节。

本文将探讨如何将Stripe元素整合到ASP.NETCore blazor应用程序中。

前提条件

为了更好地理解这篇文章,你将需要。

  • 安装[Microsoft Visual Studio]
  • [.NET 5 SDK]
  • 基本的[Javascript]知识
  • 基本的[C#]知识
  • 一个Stripe测试账户。

一个自定义的表格

一个自定义的结账表格有一个卡片输入字段,用于添加卡片的详细信息,一个名字输入字段,用于输入你的名字,一个电子邮件字段和一个电话号码字段。下图简要说明了结账表格的样子。这个表格有助于我们了解我们想要实现的东西。

A custom checkout form

付款收集工作流程

当我们在支付页面上点击发送时,我们将信息提交给服务器。在服务器上,我们正在创建一个付款意向。一个付款意向是一个服务对象,代表了一个付款在创建时可能处于的不同状态,即

  • 已创建
  • 等待确认
  • 已确认
  • 已完成

当一个支付意向被返回时,我们将使用特殊客户的秘密属性和Stripe元素中的Stripe javascript来确认卡的支付细节。

在卡的详细信息被确认后,支付意向将返回完成;否则,它将返回失败。下面的图片说明了Stripe元素的付款收集工作流程。

Payment collection workflow

一个blazor应用程序的例子

为了在我们的结账表单中实现Stripe元素,我们需要创建一个样本的blazor应用程序,使我们能够执行这一操作。

首先,我们需要打开Microsoft Visual Studio并选择Create new project ,如下图所示。

New blazor project

在点击Create new Project ,在下一个屏幕上选择Blazor Server App ,然后点击Next ,如下图所示。

Type of application

下一个屏幕要求我们输入应用程序的名称,输入名称后点击Next 。对于这个项目,我们将把我们的应用程序命名为CheckOutForm ,如下图所示。

Name of Application

在下一个屏幕上,我们需要为我们的应用程序选择目标框架,选择.Net Core 5.0(Current support) ,然后点击Create ,如下图所示。

Target framework

当我们在网络浏览器上调试我们的应用程序时,会出现如下图所示的情况。

App appearance

在我们的blazor应用程序中添加Stripe元素到我们的结帐表单中

我们可以在我们刚刚创建的应用程序中计算和获取数据,但我们不能将其货币化。这就是Stripe元素的作用。我们将在我们的应用程序中使用Stripe来获取报酬。

我们需要创建的第一件事是我们的支付页面。要做到这一点,我们将在我们的页面文件夹中添加一个页面,并将其命名为PaymentPage.razor ,其中将包含以下代码。

@page "/pay"
@inherits PaymentBase
<h1>Purchase Our products</h1>
<StripeConstituent _subRequest="BillingInfo" @ref="StripePaymentBase" PaymentProcessed="SendSubToServerAsync"></StripeConstituent>

我们还将在与PaymentPage.razor 相同的文件夹中创建另一个名为PaymentPage.razor.cs 的文件。这个文件有一个Stripe成员和一个Stripe计费请求,我们将创建这个文件。我们还将在这个文件中初始化支付信息以及将信息发送到服务器的占位符。

下面的代码将帮助实现这些信息。

namespace CheckOutForm.Client.Pages
{
    public class PaymentPageBase : ConstituentBase
    {
        protected StripeConstituent StripePaymentBase;
        [Inject] NavigationManager _navigationManager { get; set; }
        [Inject] HttpClient _httpClient { get; set; }
        protected StripeBillingRequest BillingInfo;
        protected override void OnInitialized()
        {
            BillingInfo = new();
            base.OnInitialized();
        }
        private async Task<APIResultModel> PostToBackend(string url, string jsonPayload)
        {
            APIResultModel apiResult = new APIResultModel();
            HttpResponseMessage responseMessage;
            HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, url);

            try
            {
                requestMessage.Content = new StringContent(jsonPayload,
                    Encoding.UTF8, "application/json");
                responseMessage = await SendMessageAsync(requestMessage);
                apiResult.Message = await responseMessage.Content.ReadAsStringAsync();
                apiResult.Success = responseMessage.IsSuccessStatusCode;
            }
            catch (Exception ex)
            {
                apiResult.Success = false;
                if (ex.Message.Contains("One or more errors"))
                {
                    apiResult.Message = ex.InnerException.Message;
                }
                else if (ex.Message.Equals("The requested message is already send."))
                {
                    apiResult.Message = "An error occurred while contacting the server. Please try again later. Thank you.";
                }
                else
                {
                    apiResult.Message = ex.Message;
                }
            }
            return apiResult;
        }
        private async Task<HttpResponseMessage> SendMessageAsync(HttpRequestMessage requestMessage)
        {
            HttpResponseMessage response;
            response = await _httpClient.SendAsync(requestMessage);
            return response;
        }
    }
}

我们要做的另一件事是创建一个StripeConstituent.razor 文件。这个文件将包含持卡人姓名、电子邮件和卡的元素。这在下面的HTML代码中实现。

<div class="row">
    <div class="col-sm-6 col-lg-6 col-md-6">
        <EditForm Model="@_subRequest">
            <ChildContent Context="EditContext">
                <DataAnnotationsValidator />
                <div class="row">
                    <div class="col-sm-6 col-lg-6 col-md-6">
                        <div class="form-group">
                            <label for="CreditCardholderName"> Credit Card Holder Name</label>
                            <InputText id="CreditCardHolderName" class="form-control" @bind-Value="@_subRequest.PaymentName" placeholder="Enter the Full Name of the Cardholder"></InputText>
                        </div>
                        <ValidationMessage For="@(() => _subRequest.PaymentName)" />
                    </div>
                    <div class="col-sm-6 col-lg-6 col-md-6">
                        <div class="form-group">
                            <label for="payment-email">Email to be notified</label>
                            <InputText id="payment-email" class="form-control" @bind-Value="@_subRequest.PaymentEmail" placeholder="Enter the Email of the Cardholder"></InputText>
                        </div>
                        <ValidationMessage For="@(() => _subRequest.paymentEmail)" />
                    </div>
                </div>
            </ChildContent>
        </EditForm>
    </div>
    <div class="col-sm-3 col-lg-3 col-md-3">
        <div class="form-group">
            <label for="card-element">Card Details</label>
            <div id="card-element" style="display: block;
                                          width: auto;
                                          padding: 0.52rem  .75rem;
                                          font-size: 2rem;
                                          line-height: 1.4;
                                          color: #606060;
                                          background-color: #808080;
                                          background-clip: padding-box;
                                          border: 1px solid #0f0f;
                                          border-radius: .25rem;
                                          transition: border-color .20s ease-in-out,box-shadow .20s ease-in-out;">
            </div>
            <div id="card-element-errors" role="alert" color="red"></div>
            <div style="height:11px">
            </div>
        </div>
    </div>
    <div class="col-sm-3 col-lg-3 col-md-3">
        <button @onclick="ProcessPaymentAsync" style="margin-top: 50px;" class="btn btn-primary">Buy</button>
    </div>
</div>

在上面的代码中,我们有一个为我们购买的订单付款的按钮,这将使我们能够处理付款。

我们还需要创建一个扩展了StripeConstituent 的局部类。在这个类中,我们将有我们的JavaScript运行时间,这就是我们传递JavaScript的地方。

我们还将传入帐单信息,准确地说,是我们在这个类中从支付页面获得的布尔信息。

我们将有一个回调函数,每当付款被处理时就会调用。因此,我们必须先等待Stripe处理该付款,以确保当前的信用卡是有效的。

如果当前的信用卡是有效的,回调函数就会给出我们发送给服务器的支付标识符。我们从不接触信用卡号码,因为它都是由Stripe开发的。

我们还将有一个布尔值用于初始时间的使用,因为只有在你第一次渲染页面时,你才想创建卡片。因此,我们将把这个布尔值设置为真。

StripeConstituent.razor.cs 文件中,我们要做的最后一件事是通过调用将创建信用卡元素的Javascript中的initialize来渲染布尔值。

我们将创建一个函数,在用户点击Buy 按钮后处理付款。这将通过函数public async Task ProcessPaymentAsync() 下的代码来实现。

我们将在StripeConstituent.razor.cs 文件中使用下面的代码片断来实现它。

namespace CheckOutForm.Client.Constituent
{
    public partial class StripeConstituent : IDisposable
    {
        [Inject] IJSRuntime _js { get; set; }
        [Parameter] public StripeBillingRequest _subRequest { get; set; }
        [Parameter] public EventCallback<bool> PaymentProcessed { get; set; }
        protected bool _initialTime;
        private DotNetObjectReference<StripeComponent> _objRef;
        protected override async Task OnInitializedAsync()
        {
            _initialTime = true;
        }
        public void Dispose()
        {
            _objRef?.Dispose();
        }
        public async Task ProcessPaymentAsync()
        {
            _objRef = DotNetObjectReference.Create(this);
            await _js.InvokeVoidAsync("createPaymentMethodServer", _objRef, _subRequest.BillingEmail, _subRequest.BillingName);
        }
        protected override async Task OnAfterRenderAsync(bool initialRender)
        {
            if (_initialTime)
            {
                _initialTime = false;
                await _js.InvokeVoidAsync("Initiate");
            }
        }
        [JSInvokable("Subscribe")]
        public Task Subscribe(string paymentIdentifier)
        {
            _subRequest.BillingMethod = paymentIdentifier;
            return PaymentProcessed.InvokeAsync(true);
        }
    }
}

我们将在wwwroot 文件夹中创建另一个文件,并将其命名为script.js

在这个文件中,我们将首先初始化我们将要使用的变量。它是初始化Stripe的公钥的地方。公钥是从我们创建的Stripe账户中找到的。

然后我们设置Stripe元素,并对我们的卡片元素应用必要的样式,使其看起来不错。下面的代码将帮助实现这一点。

let stripe, user, amount, card;
stripe = window.Stripe('pk_test_51HsZbzBkXnJ98OJr1J1FhgukggfdtyuVfiCSxqyAKyvtVQukCfdsyjgfssdfdyjDt5cRqJ5HT7aSclkwIlgssfvfg7OXmqbfX00KesyaFAy');
let elements = stripe.elements();
let  style = {
    base: {
        color: '#ffff',
        fontFamily: 'system-ui, Georgia, "Gill Sans" ',
        fontSmoothing: 'auto',
        fontSize: '20px',
        '::placeholder': {
            color: '#0000ff'
        }
    },
    invalid: {
        color: '#808080',
        iconColor: '#808080'
    }
};

在启动时,我们调用了下面的函数;该函数创建了信用卡元素并弹出了信用卡号码、CVV和卡片的有效日期。我们还将检查卡上的错误,并显示它们。

let newcard = true;
function Initiate() {
    if (newcard) {
        card = elements.create('card', { style: style });
        newcard = false;
    }
    card.mount('#card-element');
    card.on('change', function (event) {
        errorHandler(event);
    });
}

我们将在JavaScript文件中创建一个函数,处理支付过程中的任何错误。我们将使用下面的代码。

function errorHandler(event) {

    let errorHandler = document.getElementById('card-element-errors');

    if (event.error) {
        errorHandler.textContent = event.error.message;
    } else {
        errorHandler.textContent = '';
    }
}

下面代码片断中的卡片元素是JavaScript将寻找的东西。createPaymentMethod 正在调用stripe.createBillingMethod ,在没有错误的情况下,它从dotnetHelper 中调用信用卡订阅,并传递计费方法标识符。

function createPaymentMethod(dotnetHelper, cardElement, billingEmail, billingName)
{
    return stripe
        .createBillingMethod({
            type: 'card',
            card: cardElement,
            payment_details: {
                name: paymentName,
                email: paymentEmail,
            },
        })
        .then((result) => {
            if (result.error) {
                errorHandler(result);
            } else {
                createSubscription(dotnetHelper, result.billingMethod.id );
            }
        });
}

我们需要创建一个计费方法服务器并传入dotnetHelper,paymentEmail,paymentName

function createBillingMethodServer(dotnetHelper, paymentEmail, paymentName)
{
    createBillingMethod(dotnetHelper, card, paymentEmail, paymentName);
}

function createSubscription(dotnetHelper, BillingMethodIdentifier)
{
    dotnetHelper.invokeMethodAsync('Subscribe', paymentMethodIdentifier);
    dotnetHelper.dispose();
}

现在,最后要做的是到index.html 文件中,在html 代码的头部添加javascript链接。

    <script src="https://js.stripe.com/v3/"></script>
    <script src="stripescript.js"></script>

税收是如何处理的

当我们谈论国际支付时,税收是最需要记住的事情。然而,使用Stripe元素,税收问题很容易处理。

Stripe元素使您能够配置您所在的地方,它为您定制每一个地区和阈值,在那里您将开始支付税收。这有助于它根据客户的送货地址自动应用税收。

当我们用Stripe元素构建自己的结账表单时,我们需要确定客户的位置,以便向客户呈现正确的税收。

一个新的Stripe功能正在开发中,它对美国的税款汇出有支持。这个功能可以收集税款并将其支付给我们在美国的公司。

总结

从这篇文章中可以看出,在Stripe元素的帮助下,企业可以轻松实现来自世界不同地区的现金流动,这些地区遵守政府政策和法规。此外,由于税收是根据运输目的地来计算的,所以这更容易。