Skip to content
返回构建教程

支付集成

通过 Stripe/RevenueCat 收款,带幂等、webhook 验证和对账。

为什么

支付 bug 向真人收真钱,双重扣款是支持工单加拒付加流失客户。幂等键在网络重试发同一请求两次时防双重扣款。webhook 验证防攻击者发假'支付成功'免费获得订阅。对账(每日比 DB 与提供方面板)在成账单纠纷前抓静默漂移。每个都是一次性设置,防一类事件,修复成本是预防的 10-100 倍。

何时使用

应用收钱时。正确 Stripe 集成约 4-8 小时。永不跳过——半个支付集成比没有更糟。

如何做

1. 用提供方 SDK,永不裸 API 调用——SDK 处理签名、重试和版本
   - Stripe:pnpm add stripe;用 env 的 secret key 初始化
   - 创建扣款时总设幂等键(用你的订单 ID)

2. 服务端创建 checkout session,客户端重定向到它
   - 永不自建卡表单——PCI 范围从 SAQ-A 爆炸到 SAQ-D
   - 用 Stripe Checkout 或 Payment Element;卡号永不碰你服务器

3. 为 payment_intent.succeeded、invoice.paid、customer.subscription.deleted 设 webhook
   - 用 stripe.webhooks.constructEvent(rawBody, sig, secret) 验签
   - 用原始 body,非 JSON 解析——验签需精确字节

4. 让 webhook handler 幂等:检查事件 ID 是否已处理
   - 处理过的事件 ID 存 DB 表;已见即跳过
   - 这处理 Stripe 重试 webhook(任何 5xx 它都会重试)

5. 跑每日对账 job:从 Stripe 列扣款,比你的订单表
   - 任何不匹配告警(Stripe 付了但 DB 没有,或反之)

示例

// 带幂等创建 checkout
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function createCheckout(orderId: string, amount: number) {
  return stripe.checkout.sessions.create({
    mode: "payment",
    line_items: [{ price_data: { currency: "usd", unit_amount: amount, product_data: { name: "订单 " + orderId } }, quantity: 1 }],
    success_url: `${env.URL}/success?o=${orderId}`,
    cancel_url: `${env.URL}/cancel`,
  }, { idempotencyKey: `checkout_${orderId}` });
}

// Webhook handler(验签、幂等)
export async function handleWebhook(rawBody: Buffer, sig: string) {
  const event = stripe.webhooks.constructEvent(rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET!);
  if (await isProcessed(event.id)) return;  // 幂等
  if (event.type === "payment_intent.succeeded") await fulfillOrder(event.data.object);
  await markProcessed(event.id);
}

常见问题

  • ⚠验签前 JSON 解析 webhook body,签名校验在修改后的字节上失败。
  • ⚠不用幂等键,网络抖动重试双重扣客户。
  • ⚠在 checkout 重定向而非 webhook 里履约——用户关标签页,订单永不履约。
  • ⚠存卡号'让重复 checkout 更容易'——这是 PCI-DSS 违规可致罚款。

最佳实践

  • ✓CI 里用 Stripe Test Mode + 测试卡(4242...),每个碰计费的 PR 跑完整购买 e2e。
  • ✓记每个状态转换(pending → succeeded → fulfilled)含 Stripe 事件 ID 供审计追溯。
  • ✓设 Stripe 客户门户让用户自助取消——支持工单减 60%。
  • ✓监控 webhook 端点 5xx 率;Stripe 72h 内失败 >80% 会禁 webhook,静默坏计费。