# 不进行银行验证的银行卡付款 构建一个带有区域限制的稍简单的集成。 这种集成支持仅接受美国和加拿大银行卡的企业。它的构建更简单,但无法扩展以支持全球客户群。 ### 此集成的运作方式 欧洲和印度等地区的银行通常需要双重验证来确认购买。如果您主要在美国和加拿大开展业务,忽略 *银行卡验证* (A bank might require the customer to authenticate a card payment before processing. Implementation varies by bank but commonly consists of a customer entering in a security code sent to their phone) 可以简化您的集成,因为这些地区的银行很少要求验证。 当银行要求验证时,此基础集成会立即拒绝付款(类似于银行卡拒付),而不是处理身份验证来异步完成付款。这样做的好处是,付款会立即成功或失败,付款确认在服务器上进行,因此您无需使用 *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) 即可立即处理付款后操作。 ### 与全球集成的比较 | 功能 | 本集成 | 全球集成 | | -------------------- | --- | ---- | | 自定义支付表单 | ✔ | ✔ | | 敏感数据永不接触您的服务器 | ✔ | ✔ | | 适用于美国和加拿大客户 | ✔ | ✔ | | 拒绝银行卡信息错误或银行卡资金不足的付款 | ✔ | ✔ | | 拒绝要求银行验证的付款 | ✔ | | | 适用于全球客户 | | ✔ | | 自动处理需要银行验证的银行卡付款 | | ✔ | | 建议用 Webhook 处理付款后任务 | | ✔ | | 轻松扩展到其他支付方式(例如银行借记) | | ✔ | 增长中的企业或全球性企业应使用 Stripe 的[全球集成](https://docs.stripe.com/payments/accept-a-payment.md)来支持银行的双重验证请求,并允许客户用更多支付方式付款。 您正在构建的付款流程 (See full diagram at https://docs.stripe.com/payments/without-card-authentication) ## 构建结账表单 [客户端] [Elements](https://docs.stripe.com/payments/elements.md) 是 Stripe.js 的一部分,它提供了用来从客户那里收集银行卡信息的临时 UI 组件。Stripe 托管它们并将其作为 iframe 放入您的支付表单,从而使您的客户的银行卡详情不会触及您的代码。 #### HTML + JS 先在您网站的每个页面头部包含 [Stripe.js](https://docs.stripe.com/js.md) 脚本。 ```html ``` 在网站的每个页面上包含脚本的好处是您可以利用 Stripe 的[高级防欺诈功能](https://docs.stripe.com/radar.md)以及检测异常浏览行为的功能。 ### 安全要求 为保证 [PCI 合规](https://docs.stripe.com/security/guide.md),请始终直接从 **js.stripe.com** 下载此脚本。不要将脚本打包或自行托管副本。 使用 Elements 时,所有的支付信息都会通过一个安全的 HTTPS 连接来提交。 包含 Elements 的页面的地址必须以 **https://** 开头,不能是 **http://**。有关获取 SSL 证书并与您的服务器集成以启用安全 HTTPS 连接的更多信息,请查看[安全](https://docs.stripe.com/security.md)文档。 ### 将 Elements 添加到您的页面 然后,您需要有 Stripe 账户。[立即注册](https://dashboard.stripe.com/register)。 用您的支付表单中的唯一 ID 创建一个空的 DOM Elements(容器)。 ```html

``` 创建一个 [Stripe 对象](https://docs.stripe.com/js.md#stripe-function)实例,提供您 [API 公钥](https://docs.stripe.com/keys.md)作为第一个参数。之后,创建一个 [Elements 对象](https://docs.stripe.com/js.md#stripe-elements)实例,并用它在页面上的空 DOM Element 容器中[挂载](https://docs.stripe.com/js.md#element-mount)一个 Card 元素。 ```javascript const stripe = Stripe('<>'); const elements = stripe.elements(); const cardElement = elements.create('card'); cardElement.mount('#card-element'); ``` 在客户提交支付表单时,用您的客户端 [stripe.createPaymentMethod](https://docs.stripe.com/js/payment_methods/create_payment_method) 收集银行卡详情并创建一个 [PaymentMethod](https://docs.stripe.com/api/payment_methods.md)。将 PaymentMethod 的 ID 发送到您的服务器。 ```javascript const form = document.getElementById("payment-form"); var resultContainer = document.getElementById('payment-result'); // cardElement is defined in the previous step cardElement.on('change', function(event) { if (event.error) { resultContainer.textContent = event.error.message; } else { resultContainer.textContent = ''; } }); form.addEventListener('submit', async event => { event.preventDefault(); resultContainer.textContent = ''; const result = await stripe.createPaymentMethod({ type: 'card', card: cardElement, }); handlePaymentMethodResult(result); }); const handlePaymentMethodResult = async ({ paymentMethod, error }) => { if (error) { // An error happened when collecting card details, show error in payment form resultContainer.textContent = error.message; } else { // Send paymentMethod.id to your server (see Step 3) const response = await fetch("/pay", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ payment_method_id: paymentMethod.id }) }); const responseJson = await response.json(); handleServerResponse(responseJson); } }; const handleServerResponse = async responseJson => { if (responseJson.error) { // An error happened when charging the card, show it in the payment form resultContainer.textContent = responseJson.error; } else { // Show a success message resultContainer.textContent = 'Success!'; } }; ``` #### React 先安装 [Stripe.js](https://github.com/stripe/stripe-js) 和 [React Stripe.js](https://docs.stripe.com/sdks/stripejs-react.md)。 ```bash npm install --save @stripe/stripe-js @stripe/react-stripe-js ``` > 本指南假设您已经具备 React 的基本工作知识,并且您已经设置好了一个 React 项目。如果您是 React 的新手,我们建议您先阅读 React [开始使用](https://reactjs.org/docs/getting-started.html)指南,然后再继续。 > > 如果您正在寻找一种无需构建新项目即可快速试用 React Stripe.js 的方法,请从 [CodeSandbox 的演示](https://codesandbox.io/s/react-stripe-official-q1loc?fontsize=14&hidenavigation=1&theme=dark)开始。 ### 安全要求 使用 Elements 时,所有的支付信息都会通过一个安全的 HTTPS 连接来提交。 包含 Elements 的页面的地址必须以 **https://** 开头,不能是 **http://**。有关获取 SSL 证书并与您的服务器集成以启用安全 HTTPS 连接的更多信息,请查看[安全](https://docs.stripe.com/security.md)文档。 ### 加载 Stripe.js 并将 Elements 添加到您的页面 要使用 Elements,请将您的 React 应用的根目录包装在 [Elements](https://docs.stripe.com/sdks/stripejs-react.md#elements-provider) 提供程序中。用您的公钥调用 [loadStripe](https://github.com/stripe/stripe-js#loadstripe)然后将返回的 `Promise` 传递给 `Elements` 提供程序。 在您的 React 应用的根目录中导入并调用 `loadStripe`,以利用 Stripe 的[高级防欺诈功能](https://docs.stripe.com/radar.md)以及检测异常浏览行为的功能。 ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import {Elements} from '@stripe/react-stripe-js'; import {loadStripe} from '@stripe/stripe-js'; import CheckoutForm from './CheckoutForm'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe("<>"); function App() { return ( ); }; ReactDOM.render(, document.getElementById('root')); ``` ### 创建 PaymentMethod 在客户提交支付表单时,用您的客户端 `CardElement` 和 [stripe.createPaymentMethod](https://docs.stripe.com/js/payment_methods/create_payment_method) 收集银行卡详情并创建一个 [PaymentMethod](https://docs.stripe.com/api/payment_methods.md)。将 PaymentMethod 的 ID 发送到您的服务器。 从您的支付表单组件调用 `stripe.createPaymentMethod` 时,使用 [useStripe](https://docs.stripe.com/sdks/stripejs-react.md#usestripe-hook) and [useElements](https://docs.stripe.com/sdks/stripejs-react.md#useelements-hook) hook。如果您不想用 hooks,而是想使用传统的类组件 (Class Components),则可以使用 [ElementsConsumer](https://docs.stripe.com/sdks/stripejs-react.md#elements-consumer)。 #### Hooks ```jsx import React from 'react'; import {useStripe, useElements, CardElement} from '@stripe/react-stripe-js'; export default function CheckoutForm() { const stripe = useStripe(); const elements = useElements(); const handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); const result = await stripe.createPaymentMethod({ type: 'card', card: elements.getElement(CardElement), billing_details: { // Include any additional collected billing details. name: 'Jenny Rosen', }, }); handlePaymentMethodResult(result); }; const handlePaymentMethodResult = async (result) => { if (result.error) { // An error happened when collecting card details, // show `result.error.message` in the payment form. } else { // Otherwise send paymentMethod.id to your server (see Step 3) const response = await fetch('/pay', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ payment_method_id: result.paymentMethod.id, }), }); const serverResponse = await response.json(); handleServerResponse(serverResponse); } }; const handleServerResponse = (serverResponse) => { if (serverResponse.error) { // An error happened when charging the card, // show the error in the payment form. } else { // Show a success message } }; const handleCardChange = (event) => { if (event.error) { // Show `event.error.message` in the payment form. } }; return (
); } ``` ## 设置 Stripe [服务器端] 用官方库请求从您的应用程序访问 Stripe API: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ## 付款 [服务器端] 在您的服务器上设置一个端点,用以接收来自客户的请求。 Stripe 用一个 [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) 对象来表示您从客户收款的意图,跟踪扣款尝试及整个过程中付款状态的变化情况。 始终在服务器端决定扣款金额,这是一个可信的环境,客户端不行。这样可防止客户自己选择价格。 创建一个 HTTP 端点,响应第 1 步的 AJAX 请求。在此端点,应决定对客户的扣款金额。创建付款时,使用第 1 步的 *PaymentMethod* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) ID 创建一个 PaymentIntent,使用以下代码: #### curl ```curl # Check the status of the PaymentIntent to make sure it succeeded curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -d amount=1099 \ -d currency=usd \ # A PaymentIntent can be confirmed some time after creation, # but here we want to confirm (collect payment) immediately. -d confirm=true \ -d payment_method="{{PAYMENT_METHOD_ID}}" \ # If the payment requires any follow-up actions from the # customer, like two-factor authentication, Stripe will error # and you will need to prompt them for a new payment method. -d error_on_requires_action=true ``` > 如果您在确认付款时将 [error_on_requires_action](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-error_on_requires_action) 设置为 `true`,则如果 Stripe 要求用户进行双重验证,则付款将自动失败。 #### Payment Intents API 响应 在您用 API 进行付款时,响应中会包含 PaymentIntent 的状态。如果付款成功,则它的状态变为 `succeeded`。 ```json { "id": "pi_0FdpcX589O8KAxCGR6tGNyWj", "object": "payment_intent", "amount": 1099, "charges": { "object": "list", "data": [ { "id": "ch_GA9w4aF29fYajT", "object": "charge", "amount": 1099, "refunded": false, "status": "succeeded", } ] }, "client_secret": "pi_0FdpcX589O8KAxCGR6tGNyWj_secret_e00tjcVrSv2tjjufYqPNZBKZc", "currency": "usd", "last_payment_error": null,"status": "succeeded", } ``` 如果付款被拒绝,响应中会包含错误代码和错误消息。这里有一个由于要求对银行卡进行双重验证而付款失败的示例。 ```json { "error": {"code": "authentication_required", "decline_code": "authentication_not_handled", "doc_url": "https://docs.stripe.com/error-codes#authentication-required", "message": "This payment required an authentication action to complete, but `error_on_requires_action` was set. When you're ready, you can upgrade your integration to handle actions at https://stripe.com/docs/payments/payment-intents/upgrade-to-handle-actions.", "payment_intent": { "id": "pi_1G8JtxDpqHItWkFAnB32FhtI", "object": "payment_intent", "amount": 1099, "status": "requires_payment_method", "last_payment_error": { "code": "authentication_required", "decline_code": "authentication_not_handled", "doc_url": "https://docs.stripe.com/error-codes#authentication-required", "message": "This payment required an authentication action to complete, but `error_on_requires_action` was set. When you're ready, you can upgrade your integration to handle actions at https://stripe.com/docs/payments/payment-intents/upgrade-to-handle-actions.", "type": "card_error" }, }, "type": "card_error" } } ``` ## 测试集成 Stripe 提供了几个测试卡,您可以在*沙盒* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes)中使用,以确保此集成已准备就绪。使用时,CVC 卡安全码、邮编及未来的有效期可任意输入。 | 卡号 | 描述 | | ---------------- | ------------------------------------------------- | | 4242424242424242 | 成功并且立即处理付款。 | | 4000000000009995 | 始终会失败,显示拒付码 `insufficient_funds`。 | | 4000002500003155 | 要求验证,此集成中会失败,显示拒付代码 `authentication_not_handled`。 | 查看完整的[测试卡](https://docs.stripe.com/testing.md)列表。 ## 将集成升级以处理银行卡验证 基本银行卡支付集成现已完成。此集成会 **拒绝支付过程中要求验证的银行卡** 。 如果您开始在管理平台中看到付款列为`失败`,那么您需要[升级您的集成](https://docs.stripe.com/payments/payment-intents/upgrade-to-handle-actions.md)。Stripe 全球集成会处理这些付款,而不会自动拒绝付款。