不用 Webhook 接受银行卡付款
了解如何在您的服务器确认银行卡付款并处理银行卡验证要求。
为获得更广泛的支持并且未来可继续使用,请为异步付款使用标准集成。
这种集成在处理付款时使用的是单一的客户端到服务器流程,没有使用 webhooks 或处理离线事件。虽然看似更简单了,但随着您业务的增长,这种集成很难扩展,并且有几个限制:
- 仅支持卡 — 必须编写更多代码来分别支持 ACH 及流行的区域性支付方式。
- 重复扣款风险——通过在客户每次尝试付款时同步创建新的 PaymentIntent,您可能会意外地对客户进行重复扣款。请务必遵循最佳实践。
- 手动处理验证 — 需进行 3DS 验证或受强客户认证等法规约束的银行卡需要在客户端执行额外的步骤。
如果您打算使用这种集成,请留意这些限制。否则,请使用标准集成。
设置 Stripe服务器端客户端
服务器端
该集成要求您的服务器上的端点与 Stripe API 通讯。请用我们的官方库从您的服务器访问 Stripe API:
客户端
React Native SDK 是开源的,有完整的文档。在内部,它利用的是原生 iOS 和 Android SDK。要安装 Stripe 的 React Native SDK,在您的项目目录中运行以下某个指令(取决于您使用的软件包管理器)。
然后,安装一些其他必要的依赖项:
- 对于 iOS,前往 ios 目录并运行
pod install
,确保您也安装了所需的本地依赖项。 - 对于 Android,无需安装其他依赖项。
注意
建议按照官方 TypeScript 指南添加 TypeScript 支持。
Stripe 初始化
要在您的 React Native 应用中初始化 Stripe,使用 StripeProvider
组件包裹您的支付界面,或者使用 initStripe
初始化方法。只需要 publishableKey
中的 API 公钥。下例显示的是用 StripeProvider
组件初始化 Stripe 的方式。
import { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( <StripeProvider publishableKey={publishableKey} merchantIdentifier="merchant.identifier" // required for Apple Pay urlScheme="your-url-scheme" // required for 3D Secure and bank redirects > {/* Your app code here */} </StripeProvider> ); }
创建自己的结账页面客户端
用 CardField
在客户端安全地收集银行卡信息,这是 SDK 提供的一个 UI 组件,用于收集卡号、有效期、CVC 和邮编。
CardField
执行实时验证和格式化。
将 CardField
组件添加到您的支付界面,安全地收集客户的银行卡详情。用 onCardChange
回调函数检查卡的非敏感信息,例如品牌,以及信息是否完整。
import { CardField, useStripe } from '@stripe/stripe-react-native'; function PaymentScreen() { // ... return ( <View> <CardField postalCodeEnabled={true} placeholders={{ number: '4242 4242 4242 4242', }} cardStyle={{ backgroundColor: '#FFFFFF', textColor: '#000000', }} style={{ width: '100%', height: 50, marginVertical: 30, }} onCardChange={(cardDetails) => { console.log('cardDetails', cardDetails); }} onFocus={(focusedField) => { console.log('focusField', focusedField); }} /> </View> ); }
运行您的应用程序,确保结账页面可以显示 CardField
组件。
收集银行卡详情客户端
当您的客户准备结账时,创建一个 PaymentMethod,包含通过 CardField
组件收集的详情。
import { CardField, useStripe } from '@stripe/stripe-react-native'; function PaymentScreen() { const { createPaymentMethod, handleNextAction } = useStripe(); const pay = () => { // Gather customer billing information (for example, email) const billingDetails: CreatePaymentMethod.BillingDetails = { email: 'email@stripe.com', phone: '+48888000888', addressCity: 'Houston', addressCountry: 'US', addressLine1: '1459 Circle Drive', addressLine2: 'Texas', addressPostalCode: '77063', }; // Create payment method const { paymentMethod, error } = await createPaymentMethod({ paymentMethodType: 'Card', paymentMethodData: { billingDetails, } }); }; // ... }
向服务器提交 PaymentMethod客户端
如果 PaymentMethod 创建成功,则将它的 ID 发送到您的服务器。
// ... const pay = () => { // ... // Send the PaymentMethod to your server to create a PaymentIntent const response = await fetch(`/pay`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ paymentMethodId: paymentMethod.id }), }); const { error, requires_action, payment_intent_client_secret } = await response.json(); if (error) { // Error creating or confirming PaymentIntent Alert.alert('Error', paymentIntentError); return; } if (payment_intent_client_secret && !requires_action) { // Payment succeeded Alert.alert('Success', 'The payment was confirmed successfully!'); } if (payment_intent_client_secret && requires_action) { // ...continued below } }; // ...
创建 PaymentIntent服务器端
在您的服务器上设置一个端点来接收请求。稍后在处理需要额外验证的付款时,也会用到此端点。
用在您的客户端创建的 PaymentMethod 的 ID 创建新的 PaymentIntent。您可以通过在创建 PaymentIntent 时将 confirm 属性设置为 true 或在创建后调用 confirm 来 确认 PaymentIntent。也支持对银行卡付款进行单独授权和捕获。
如果支付需要额外的操作,如 3DS 验证,PaymentIntent 的状态将设置为 requires_
。如果支付失败,状态将设置回 requires_
,您应该向用户显示错误。如果支付不需要任何额外的验证,则创建一个收款,且 PaymentIntent 状态设置为 succeeded
。
注意
在 2019-02-11 以前的 API 版本中,requires_
显示为 requires_
,而 requires_
显示为 requires_
。
如果您想保存该卡以便以后重复使用,请创建一个 Customer 来存储 PaymentMethod,并在创建 PaymentIntent 时传递以下附加参数:
- customer。设置为 Customer 的 ID。
- setup_future_usage。设置为
off_
可告诉 Stripe 您打算在客户不在场时将这个 PaymentMethod 用于会话外付款。设置这个属性便可在确认 PaymentIntent 并且用户完成所需的任何操作后,将 PaymentMethod 保存到 Customer。详见付款后保存银行卡中的代码示例。session
处理任何后续操作客户端
您在第 4 步时在服务器上确认后,付款会直接成功。但是,一些付款流程需要客户采取额外的操作,例如用 3DS 验证进行验证。
对于需要任何后续操作的情况,PaymentIntent 的状态为 requires_
。在客户端,将 PaymentIntent 的客户端密钥传递给 handleNextAction
。原生处理程序会显示一个视图,并引导客户完成验证流程。在客户端处理完所需操作后,PaymentIntent 的状态会变为 requires_
。这使您的集成能够在后端履行订单,并将履行结果返回给客户端。
将 PaymentIntent ID 发送到您的后端,并在一个小时内再次确认,从而完成付款。否则,付款尝试失败,并回到 requires_
。
// ... const pay = () => { // ... // If PaymentIntent requires action, call handleNextAction if (payment_intent_client_secret && requires_action) { const { error, paymentIntent } = await handleNextAction(payment_intent_client_secret); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else if (paymentIntent) { if ( paymentIntent.status === PaymentIntents.Status.RequiresConfirmation ) { // Confirm the PaymentIntent again on your server const response = await fetch(`/pay`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ payment_intent_id: paymentIntent.id }), }); const { error, success } = await response.json(); if (error) { // Error during confirming Intent Alert.alert('Error', error); } else if (success) { Alert.alert('Success', 'The payment was confirmed successfully!'); } } else { // Payment succedeed Alert.alert('Success', 'The payment was confirmed successfully!'); } } } }; // ...
再次确认 PaymentIntent服务器端
该代码仅在支付需要额外验证时才执行,这与上一步的处理方式类似。该代码本身不是可选的,因为任何支付都需要这个额外步骤。
使用您在上方设置的同一个端点再次确认 PaymentIntent 以完成付款,并履行订单。请务必在尝试付款后一小时内确认。否则,付款将失败,并回到 requires_
。