金融与交易
在 TypeScript/React/Next.js…
适用于需要用 Next.js/React/TypeScript 接入 Stripe 支付、订阅计费和 Webhook 事件同步的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 TypeScript/React/N特定
解决思路
- 始终在服务端处理支付,不在客户端执行敏感收款逻辑。
- 使用 Stripe 的最新 API 版本。
- 实现完善的错误处理。
- 遵循 PCI 合规最佳实践。
- 使用 webhooks 进行可靠的事件处理。
- 服务端 Stripe 客户端配置:import Stripe from 'stripe'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2023-10-16', typescript: true });
- 创建 Payment Intent:在 app/api/create-payment-intent/route.ts 中导出 POST,解析请求体中的 amount 和 currency = 'usd',调用 stripe.paymentIntents.create({ amount, currency, automatic_payment_methods: { enabled: true } }),返回 NextResponse.json({ clientSecret: paymentIntent.client_secret })。
- 创建 Payment Intent 的错误处理:用 try/catch 包裹;catch 时返回 NextResponse.json({ error: 'Payment intent creation failed' }, { status: 500 })。
- 客户端 Stripe Elements 设置:在 'use client' 组件中从 @stripe/react-stripe-js 引入 Elements,从 @stripe/stripe-js 引入 loadStripe,执行 const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!),并用 <Elements stripe={stripePromise}>{children}</Elements> 包裹子组件。
- 支付表单组件:在 'use client' 组件中使用 PaymentElement、useStripe、useElements,维护 isLoading 和 error 状态。
- 支付表单提交:handleSubmit 中执行 e.preventDefault();若 !stripe || !elements 则 return;设置 setIsLoading(true) 和 setError(null)。
- 确认支付:调用 stripe.confirmPayment({ elements, confirmParams: { return_url: `${window.location.origin}/payment/success` } }),若 submitError 存在则 setError(submitError.message ?? 'Payment failed'),最后 setIsLoading(false)。
- 支付表单 UI:渲染 <PaymentElement />;有 error 时显示错误;提交按钮在 !stripe || isLoading 时禁用,文案为 Processing... 或 Pay Now。
- 创建订阅:createSubscription(customerId, priceId) 调用 stripe.subscriptions.create({ customer: customerId, items: [{ price: priceId }], payment_behavior: 'default_incomplete', payment_settings: { save_default_payment_method: 'on_subscription' }, expand: ['latest_invoice.payment_intent'] }) 并返回 subscription。
- 取消订阅:cancelSubscription(subscriptionId) 调用 stripe.subscriptions.cancel(subscriptionId) 并返回。
- Webhook 处理:在 app/api/webhooks/stripe/route.ts 中导出 POST,读取 const body = await request.text(),从 headers().get('stripe-signature')! 获取 signature。
- Webhook 签名验证:使用 stripe.webhooks.constructEvent(body, signature, webhookSecret) 构造 event;失败时返回 'Webhook signature verification failed',状态码 400。
- Webhook 事件分发:根据 event.type 使用 switch;payment_intent.succeeded 时取 event.data.object as Stripe.PaymentIntent 并调用 handlePaymentSuccess(paymentIntent)。
- Webhook 事件分发:customer.subscription.created 时取 event.data.object as Stripe.Subscription 并调用 handleSubscriptionCreated(subscription)。
- Webhook 事件分发:customer.subscription.deleted 时调用 handleSubscriptionCanceled(event.data.object)。
- Webhook 事件分发:invoice.payment_failed 时调用 handlePaymentFailed(event.data.object)。
- Webhook 成功响应:返回 'Webhook processed',状态码 200。
- 客户管理:createOrRetrieveCustomer(email, userId) 先调用 stripe.customers.list({ email, limit: 1 }) 查询已有客户。
- 客户管理:若 existingCustomers.data.length > 0,返回 existingCustomers.data[0]。
- 客户管理:否则调用 stripe.customers.create({ email, metadata: { userId } }) 创建并返回客户。
- 绝不在客户端暴露 secret keys。
- 始终验证 webhook signatures。
- 关键操作使用 idempotency keys。
- 实现完善的错误处理。
- 记录 payment events 以便调试。
- 开发时使用 Stripe test mode。
- 错误处理:用 try/catch 包裹 stripe.paymentIntents.create({...})。
- 错误处理:若 error instanceof Stripe.errors.StripeCardError,记录卡被拒和 error.message。
- 错误处理:若 error instanceof Stripe.errors.StripeInvalidRequestError,记录无效参数和 error.message。
- 错误处理:其他情况记录 Stripe error。
- 测试:使用 Stripe test mode 和 test card numbers。
- 测试:使用 Stripe CLI 测试 webhook events。
- 测试:实现错误场景。
- 测试:测试订阅生命周期事件。
适用边界 · 注意事项
- 不适用于非 Stripe 的支付提供商或完全不涉及支付的场景。
- 不适用于无法安全保管 STRIPE_SECRET_KEY 或无法提供服务端运行时/Webhook endpoint 的环境。
- 不适用于纯静态客户端应用且不能执行服务端支付逻辑的情况。