错误处理
Stripe 提供很多种错误。可能会反映外部事件(如付款被拒绝和卡组织中断),也可能会反映代码问题(如 API 调用无效)。
处理错误时,可以使用下表中的部分或全部方法。无论用哪个方法,您都可以遵从我们为各类错误推荐的响应方式。
方法 | 目的 | 需要时 |
---|---|---|
捕获异常 | API 调用不能继续时恢复 | 总是 |
监测 Webhook | 从 Stripe 对通知做出反应 | 有时候 |
获取存储的故障相关信息 | 调查过往问题并支持其他方法 | 有时候 |
捕获异常
如果立即发生问题,妨碍某个 API 调用继续,则 Stripe Node.js 库会引发一个异常。最佳做法是捕获并处理异常。要引发并捕获异常,请执行以下操作:引发并捕获异常,您需要做几件事:
- 如果您在一个函数中进行 API 调用,在函数定义前加上
async
关键词。 - 在 API 调用本身前面加上
await
关键词。 - 将 API 调用包在
try
/catch
块中。
捕获一个异常时,您可以用它的类型属性来选择一个响应方式。
const stripe = require('stripe')(
); async function exampleFunction(args) { try { const paymentIntent = await stripe.paymentIntents.create(args); console.log('No error.'); } catch (e) { switch (e.type) { case 'StripeCardError': console.log(`A payment error occurred: ${e.message}`); break; case 'StripeInvalidRequestError': console.log('An invalid request occurred.'); break; default: console.log('Another problem occurred, maybe unrelated to Stripe.'); break; } } }'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
设置完异常处理措施后,使用包括测试卡在内的多种数据进行测试,来模拟不同的支付结果。
监测 Webhook
Stripe 会用 Webhook 通知您很多中问题。包括那些在 API 调用后不会立即发生的问题。例如:
- 您输掉了一个争议。
- 经常性付款在成功几个月后仍可能会失败。
- 您的前端确认一笔付款,然后在发现付款失败之前就会离线。(后端仍会收到 Webhook 通知,即使不是发出 API 调用的那一个。)
您不需要处理每个 Webhook 事件类型。事实上,有些集成一个都不会处理。
在您的 Webhook 处理程序中,从 Webhook 构建器的基本步骤开始:获取一个事件对象,用事件类型查看到底发生了什么情况。然后,如果事件类型指示有错误,执行以下步骤:
- 访问 event.data.object,以检索受影响的对象。
- 使用存储的受影响对象信息来获取上下文,包括错误对象。
- 用它的类型来选择一个响应方式。
const stripe = require('stripe')(
); const express = require('express'); const app = express(); app.post('/webhook', express.json({type: 'application/json'}), (request, response) => { // Get an event object const event = request.body; // Use its type to find out what happened if (event.type == 'payment_intent.payment_failed') { // Get the object affected const paymentIntent = event.data.object; // Use stored information to get an error object const error = paymentIntent.error; // Use its type to choose a response switch (error.type) { case 'StripeCardError': console.log(`A payment error occurred: ${error.message}`); break; case 'StripeInvalidRequestError': console.log('An invalid request occurred.'); if (error.param) { console.log(`The parameter ${error.param} is invalid or missing.`); } break; default: console.log('Another problem occurred, maybe unrelated to Stripe.'); break; } } response.send(); }); app.listen(4242, () => console.log('Running on port 4242'));'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
要测试您的集成对 Webhook 事件的响应情况,您可以在本地触发 Webhook 事件。完成这个链接的设置步骤后,触发一个失败的付款,看引发的错误消息是什么。
stripe trigger payment_intent.payment_failed
A payment error occurred: Your card was declined.
获取存储的故障相关信息
很多对象存储着有关故障的信息。这就是说,如果已经发生了错误,那么您可以检索对象进行检查,了解更多信息。很多情况下,存储的信息采用的是错误对象的形式,您可以用它的类型来选择一个响应方式。
例如:
- 检索特定的支付意图。
- 通过确定 last_payment_error 是否为空,检查它是否遇到了支付错误。
- 如果为空,则记录错误,包括其类型和受影响的对象。
const stripe = require('stripe')(
); const payment_intent = await stripe.paymentIntents.retrieve("sk_test_4eC39HqLyjWDarjtT1zdp7dc") const e = payment_intent.last_payment_error if (e !== null) { console.log(`PaymentIntent ${payment_intent.id} experienced a ${e.type} error.`) }'{{PAYMENT_INTENT_ID}}'
这是一些存储了故障信息的常见对象。
对象 | 属性 | 值 |
---|---|---|
支付意图 | last_payment_error | 错误对象 |
设置意图 | last_setup_error | 错误对象 |
账单 | last_finalization_error | 错误对象 |
设置尝试 | setup_error | 错误对象 |
提现 | failure_code | 提现失败代码 |
退款 | failure_reason | 退款失败代码 |
要测试使用了存储的故障信息的代码,通常需要模拟失败的交易。一般可以用测试卡或测试银行账号进行。例如:
错误类型及解决方案
在 Stripe Node.js 库中,每个错误对象都有一个 type
属性。用各类别的文档,查看相应的解决建议。
名称 | 类型 | 描述 |
---|---|---|
支付错误 | 支付过程中发生了错误,涉及这些情况中的某一种: | |
无效请求错误 | 您的 API 调用是用错误的参数、在错误的状态下,或以一种无效的方式发起的。 | |
连接错误 | 您的服务器与 Stripe 之间发生了网络问题。 | |
API 错误 | Stripe 这一端出错了。(这种情况比较少见。) | |
验证错误 | Stripe 无法用您提供的信息对您进行验证。 | |
幂等性错误 | 您将幂等性密钥用在了意外操作中,例如重放某个请求但传递的是不同的参数。 | |
权限错误 | 该请求中使用的 API 密钥没有必需的权限。 | |
速率限制错误 | 您短时间内进行的 API 调用太多。 | |
签名验证错误 | 您使用的是 Webhook 签名验证,无法验证该 Webhook 事件的可信性。 |
支付错误
支付错误(因历史原因,有时被称为“银行卡错误”)涵盖了很多常见的问题。它们分为三类:
要区分这些类别或获取更多响应信息,请参阅错误代码、拒付代码和扣款结果。
(要查看某个错误对象产生的扣款结果,先找到涉及的 Payment Intent和它最近创建的 Charge。见下方的演示示例)。
const stripe = require('stripe')(
); async function exampleFunction(args) { try { const paymentIntent = await stripe.paymentIntents.create(args); } catch (e) { console.log(e) const charge = await stripe.charges.retrieve(e.payment_intent.latest_charge) if (e.type === 'StripeCardError') { if (charge.outcome.type === 'blocked') { console.log('Payment blocked for suspected fraud.') } else if (e.code === 'card_declined') { console.log('Payment declined by the issuer.') } else if (e.code === 'expired_card') { console.log('Card expired.') } else { console.log('Other card error.') } } } }'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
API 版本 2022-08-01 或更早版本的用户:
(要查看某个错误对象产生的扣款结果,先找到涉及的 Payment Intent和它最近创建的 Charge。见下方的演示示例)。
const stripe = require('stripe')(
); async function exampleFunction(args) { try { const paymentIntent = await stripe.paymentIntents.create(args); } catch (e) { console.log(e) if (e.type === 'StripeCardError') { if (e.payment_intent.charges.data[0].outcome.type === 'blocked') { console.log('Payment blocked for suspected fraud.') } else if (e.code === 'card_declined') { console.log('Payment declined by the issuer.') } else if (e.code === 'expired_card') { console.log('Card expired.') } else { console.log('Other card error.') } } } }'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
您可以用测试卡模拟一些常见类型的支付错误。可参考这些列表中的选项:
下面的测试代码演示了一些可能的情况。
付款因疑似欺诈被阻止
类型 |
|
代码 |
|
代码 |
|
问题 | Stripe 的欺诈预防系统 Radar 阻止了付款 |
解决方案 | 当您的集成正确运行的情况下可能会发生这种错误。捕获它,然后提示客户换一个支付方式。 要减少阻止的合法付款,可尝试这些操作:
Radar 风控团队版客户还有以下额外的选项: 您可以用模拟欺诈的测试卡来测试您的集成的设置情况。如果您有自定义 Radar 规则,则遵从 Radar 文档中的测试建议。 |
付款被发卡行拒绝
类型 |
|
代码 |
|
问题 | 发卡行拒绝了付款。 |
解决方案 | 当您的集成正确运行的情况下可能会发生这种错误。它反映的是发卡行的行为,而且该行为可能是合法的。用拒付代码确定下一步如何合适。查看拒付代码文档中各代码的正确响应方式。 您还可以:
用模拟成功然后被拒绝的付款的测试卡,测试您的集成处理银行拒付的情况。 |
其他支付错误
类型 |
|
问题 | 发生了另一个支付错误。 |
解决方案 | 当您的集成正确运行的情况下可能会发生这种错误。用错误代码确定下一步如何合适。查看错误代码文档中各代码的正确响应方式。 |
无效请求错误
类型 |
|
问题 | 您的 API 调用是用错误的参数、在错误的状态下,或以一种无效的方式发起的。 |
解决方案 | 多数情况下,问题是关于请求本身的。要么是它的参数无效,要么它不能在您的集成的当前状态下执行。
|
连接错误
类型 |
|
问题 | 您的服务器与 Stripe 之间发生了网络问题。 |
解决方案 | 将 API 调用的结果视为不确定的。也就是说,不要假定它成功了或失败了。 要知道是否成功,您可以:
为更方便地恢复连接问题,您可以:
该错误可能会掩盖其他错误。可能会发生这种情况,即解决掉连接错误后,会出现其他一些错误。检查所有方案中的错误,与您在原始请求中的操作一样。 |
API 错误
类型 |
|
问题 | Stripe 这一端出错了。(这种情况比较少见。) |
解决方案 | 将 API 调用的结果视为不确定的。也就是说,不要假定它成功了或失败了。 依靠 Webhook 来获取结果信息。只要有可能,在我们解决掉一个问题时,Stripe 就会为我们创建的任何新对象触发 Webhook。 要让您的集成在特殊情况能够具有稳健性,请查看此关于服务器错误的高级讨论。 |
验证错误
幂等性错误
类型 |
|
问题 | 您将幂等性密钥用在了意外操作中,例如重放某个请求但传递的是不同的参数。 |
解决方案 |
|
权限错误
类型 |
|
问题 | 该请求中使用的 API 密钥没有必需的权限。 |
解决方案 |
速率限制错误
类型 |
|
问题 | 您短时间内进行的 API 调用太多。 |
解决方案 |
签名验证错误
类型 |
|
问题 | 您使用的是 Webhook 签名验证,无法验证该 Webhook 事件的可信性。 |
解决方案 | 当您的集成正确运行的情况下可能会发生这种错误。如果您使用的是 Webhook 签名验证,那么当有第三方尝试给您发送虚假或恶意的 Webhook 时,就会发生验证失败问题,进而引发这个错误。捕获它,并用 如果意外收到该错误(例如,用 Webhook 检测到来自于 Stripe 的错误),那么请查看检查 Webhook 签名文档,获取更多建议。尤其要确保您使用的是正确的端点私钥。它不同于您的 API 密钥。 |