You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Stripe Webhook联动AWS服务更新DynamoDB付费状态失败排查

问题排查:Stripe Webhook触发404导致DynamoDB支付状态未更新

背景情况

网站表单提交后会写入DynamoDB表,默认paid字段设为false,前端核心状态管理代码片段:

const Home: React.FC = () => {
  const [file, setFile] = useState<File | null>(null);
  const [email, setEmail] = useState<string>('');
  const [petName, setPetName] = useState<string>('');
  const [videoKey, setVideoKey] = useState<string>('');
  const [isUploading, setIsUploading] = useState<boolean>(false);

实现逻辑:Stripe Webhook + API Gateway + Lambda

通过监听Stripe支付成功事件,将DynamoDB中对应条目的paid字段更新为true,Lambda代码如下:

// index.mjs
import AWS from 'aws-sdk';
import Stripe from 'stripe';

// Initialize Stripe with your secret key
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2020-08-27' });

// Initialize AWS SDK
const dynamoDB = new AWS.DynamoDB.DocumentClient();

// Helper function to update the 'paid' status in DynamoDB
const updatePaymentStatus = async (userId, videoId, paidStatus) => {
  const params = {
    TableName: 'petsafaritable1', // Your DynamoDB table name
    Key: { userId, videoId },
    UpdateExpression: 'set paid = :p',
    ExpressionAttributeValues: {
      ':p': paidStatus,
    },
  };
  return dynamoDB.update(params).promise();
};

export const handler = async (event) => {
  let stripeEvent;

  try {
    // Verify the event with Stripe to make sure it's legitimate
    const sig = event.headers['Stripe-Signature'];
    stripeEvent = stripe.webhooks.constructEvent(event.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
  } catch (err) {
    console.error(`Webhook Error: ${err.message}`);
    return {
      statusCode: 400,
      body: `Webhook Error: ${err.message}`,
    };
  }

  // Handle the event
  if (stripeEvent.type === 'payment_intent.succeeded') {
    const paymentIntent = stripeEvent.data.object;
    const userId = paymentIntent.metadata.userId;
    const videoId = paymentIntent.metadata.videoId;

    try {
      // Update the 'paid' status in DynamoDB to true
      await updatePaymentStatus(userId, videoId, true);
      return {
        statusCode: 200,
        body: JSON.stringify({ received: true }),
      };
    } catch (updateError) {
      console.error(`Error updating payment status in DynamoDB: ${updateError.message}`);
      return {
        statusCode: 500,
        body: `Error updating payment status in DynamoDB: ${updateError.message}`,
      };
    }
  } else {
    // Ignore other event types
    return {
      statusCode: 200,
      body: `Received unhandled event type: ${stripeEvent.type}`,
    };
  }
};

问题现象

  • 已完成Lambda环境变量配置、API Gateway搭建(自定义阶段为/prod),并将Stripe Webhook URL设置为https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/prod
  • 使用测试卡(4242...)完成结账后,Stripe控制台显示Webhook交付失败,返回HTTP 404状态码,响应内容为{"message": "Not Found"}
  • 前端表单已成功写入DynamoDB初始条目,但paid字段未更新为true
  • Stripe触发的事件详情:
{
  "id": "evt_1OFml3Ej3GI2oYw2vCQ7n6RW",
  "object": "event",
  "api_version": "2023-10-16",
  "created": 1700783793,
  "data": {
    "object": {
      "id": "cs_test_a17a7e6ZPoUum328HbhqKEiecNa6WcRiHi1TEubvfK00n9bih2mninhSLe",
      "object": "checkout.session",
      "after_expiration": null,
      "allow_promotion_codes": null,
      "amount_subtotal": 2000,
      "amount_total": 2000,
      "automatic_tax": {
        "enabled": false,
        "status": null
      },
      "billing_address_collection": null,
      "cancel_url": "https://www.petsafari.tv/payment-cancelled",
      "client_reference_id": null,
      "client_secret": null,
      "consent": null,
      "consent_collection": null,
      "created": 1700783771,
      "currency": "usd",
      "currency_conversion": null,
      "custom_fields": [],
      "custom_text": {
        "shipping_address": null,
        "submit": null,
        "terms_of_service_acceptance": null
      },
      "customer": null,
      "customer_creation": "if_required",
      "customer_details": {
        "address": {
          "city": null,
          "country": "US",
          "line1": null,
          "line2": null,
          "postal_code": "12345",
          "state": null
        },
        "email": "this@that.com",
        "name": "chri sdes",
        "phone": null,
        "tax_exempt": "none",
        "tax_ids": []
      },
      "customer_email": null,
      "expires_at": 1700870171,
      "invoice": null,
      "invoice_creation": {
        "enabled": false,
        "invoice_data": {
          "account_tax_ids": null,
          "custom_fields": null,
          "description": null,
          "footer": null,
          "metadata": {},
          "rendering_options": null
        }
      },
      "livemode": false,
      "locale": null,
      "metadata": {},
      "mode": "payment",
      "payment_intent": "pi_3OFml2Ej3GI2oYw212TKJpIv",
      "payment_link": null,
      "payment_method_collection": "if_required",
      "payment_method_configuration_details": null,
      "payment_method_options": {},
      "payment_method_types": [
        "card"
      ],
      "payment_status": "paid",
      "phone_number_collection": {
        "enabled": false
      },
      "recovered_from": null,
      "setup_intent": null,
      "shipping_address_collection": null,
      "shipping_cost": null,
      "shipping_details": null,
      "shipping_options": [],
      "status": "complete",
      "submit_type": null,
      "subscription": null,
      "success_url": "https://www.petsafari.tv/payment-success?session_id={CHECKOUT_SESSION_ID}",
      "total_details": {
        "amount_discount": 0,
        "amount_shipping": 0,
        "amount_tax": 0
      },
      "ui_mode": "hosted",
      "url": null
    }
  },
  "livemode": false,
  "pending_webhooks": 3,
  "request": {
    "id": null,
    "idempotency_key": null
  },
  "type": "checkout.session.completed"
}

补充配置信息

API Gateway路由配置:

  • 配置了路径为/{proxy+}的路由,集成目标为对应Lambda函数
  • 已启用Lambda代理集成模式

排查步骤

1. 确认API Gateway路由与Webhook URL匹配

  • 检查Stripe配置的Webhook URL是否包含完整的路由路径:若API Gateway路由为/{proxy+},但仅配置根路径/prod,Stripe请求会因找不到对应路由返回404。需确认API Gateway部署的完整路径,例如若Lambda挂载在/webhook路径下,Webhook URL应为https://xxx.execute-api.us-east-1.amazonaws.com/prod/webhook
  • 登录AWS控制台,查看API Gateway的部署阶段,确认实际可访问路径与Stripe配置一致

2. 验证API Gateway集成配置

  • 确认路由的集成请求已启用Lambda代理集成:未启用的话,API Gateway无法正确转发请求到Lambda,会返回404
  • 检查路由是否允许POST方法:Stripe Webhook仅通过POST请求触发,需确保API Gateway路由开放POST方法

3. 修正Stripe事件类型处理逻辑

当前Lambda仅处理payment_intent.succeeded事件,但Stripe实际触发的是checkout.session.completed,即使路径问题解决,该事件也会被标记为未处理。需添加对应事件的处理分支:

// 在handler函数的事件判断中添加分支
} else if (stripeEvent.type === 'checkout.session.completed') {
  const checkoutSession = stripeEvent.data.object;
  const paymentIntentId = checkoutSession.payment_intent;
  // 调用Stripe API获取payment_intent的metadata
  const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);
  const userId = paymentIntent.metadata.userId;
  const videoId = paymentIntent.metadata.videoId;
  
  await updatePaymentStatus(userId, videoId, true);
  return {
    statusCode: 200,
    body: JSON.stringify({ received: true }),
  };
}

另外,当前Stripe事件的metadata为空,需确保创建Checkout Session时,将userId和videoId写入metadata,否则无法匹配DynamoDB条目:

// 创建Checkout Session时添加metadata
const session = await stripe.checkout.sessions.create({
  // 其他必填配置
  metadata: {
    userId: "用户唯一ID",
    videoId: "对应视频ID"
  }
});

4. 测试API Gateway端点可用性

使用curl或Postman发送POST请求到Webhook URL,验证端点是否可访问:

curl -X POST https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/prod \
  -H "Content-Type: application/json" \
  -d '{"test": "data"}'
  • 返回404:说明API Gateway的部署或路由配置存在问题
  • 返回其他响应:进一步排查Lambda逻辑问题

5. 查看AWS CloudWatch日志

登录AWS CloudWatch,查看对应Lambda的日志流:

  • 无日志记录:说明请求未到达Lambda,问题出在API Gateway的路由或部署环节
  • 有日志记录:查看日志中的错误信息,例如签名验证失败、DynamoDB权限不足等

内容的提问来源于stack exchange,提问作者reallymemorable

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 09:15:56