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

Django部署Vercel后Stripe Webhook签名验证失败求助

Django + React部署Vercel后Stripe Webhook签名验证失败

问题背景

我开发了一个Django+React应用,已在Django中集成Stripe支付服务,React构建产物配置为Django静态资源。本地通过Stripe CLI测试时,Webhook功能完全正常,但将Django项目部署到Vercel后,在Stripe测试后台创建Webhook端点处理事件时,持续出现签名验证错误。已确认新端点对应的webhook_secret_key配置正确,排除密钥不匹配的问题。

已尝试的无效解决方案

  • 使用request.body.decode('utf-8')作为验证用的payload
  • 使用request.data作为验证用的payload

两种方法均无法通过签名验证。

核心代码(本地正常,部署后报错)

from django.conf import settings
from django.http import HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import DepositHistory
from django.views.decorators.csrf import csrf_exempt
from decimal import Decimal
import stripe
from rest_framework.decorators import api_view
from usersAuth.models import AppUser

stripe.api_key = settings.STRIPE_SECRET_KEY

class StripeCheckoutView(APIView):
    def post(self, request):

        if self.request.user.is_authenticated:
            try:
                checkout_session = stripe.checkout.Session.create(
                    line_items=[
                        {
                            'price': 'price_1PY4d6GKlfpQfnx9EFKpod75',
                            'quantity': 1,
                        },
                    ],
                    metadata={"user": f'{self.request.user}'},
                    mode='payment',
                    success_url=settings.SITE_URL + '/?success=true&session_id={CHECKOUT_SESSION_ID}',
                    cancel_url=settings.SITE_URL + '/?canceled=true',
                )

                return Response({"url": checkout_session.url})
            except:
                return Response(
                    {'error': 'Something went wrong when creating stripe checkout session'},
                    status=status.HTTP_500_INTERNAL_SERVER_ERROR
                )
        
        return Response({'error': 'You must be logged in to pay'}, status=status.HTTP_401_UNAUTHORIZED)
    


@csrf_exempt
@api_view(['POST'])
def stripe_webhook_view(request):
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    event = None

    try:
        event = stripe.Webhook.construct_event(
            payload,
            sig_header,
            settings.STRIPE_SECRET_WEBHOOK
        )
    except ValueError as e:
        # Invalid payload
        #print('Error parsing payload: {}'.format(str(e)))
        return HttpResponse({'Error parsing payload'},status=400)
    except stripe.error.SignatureVerificationError as e:
        # Invalid signature
        #print('Error verifying webhook signature: {}'.format(str(e)))
        return HttpResponse({'Error verifying webhook signature'},status=400)

    if event['type'] == 'checkout.session.completed':
        print('we are in checkout.session.completed')
        session = event['data']['object']
        user = session.metadata.user
        amount = Decimal(session.amount_total / 100)

        appuser = AppUser.objects.get(email=user)
        DepositHistory.objects.create(user=appuser, amount=amount)
        appuser.balance += amount
        appuser.save()
    if event.type == 'payment_intent.succeeded':
        payment_intent = event.data.object # contains a stripe.PaymentIntent
        print('PaymentIntent was successful!')
    elif event.type == 'payment_method.attached':
        payment_method = event.data.object # contains a stripe.PaymentMethod
        print('PaymentMethod was attached to a Customer!')
    # ... handle other event types
    else:
        print('Unhandled event type {}'.format(event.type))


    return HttpResponse(status=200)

Webhook错误对应的请求内容

{
  "id": "evt_1PaIDNGKlfpQfnx92DWXRjHv",
  "object": "event",
  "api_version": "2024-06-20",
  "created": 1720447609,
  "data": {
    "object": {
      "id": "cs_test_a1RF6rCujYP6HqWdSmm3iZGxtdRNlpoSUlzvw09krFzU0UPgwWOyhwoIk7",
      "object": "checkout.session",
      "after_expiration": null,
      "allow_promotion_codes": null,
      "amount_subtotal": 500,
      "amount_total": 500,
      "automatic_tax": {
        "enabled": false,
        "liability": null,
        "status": null
      },
      "billing_address_collection": null,
      "cancel_url": "{url_website}/?canceled=true",
      "client_reference_id": null,
      "client_secret": null,
      "consent": null,
      "consent_collection": null,
      "created": 1720447585,
      "currency": "usd",
      "currency_conversion": null,
      "custom_fields": [
      ],
      "custom_text": {
        "after_submit": null,
        "shipping_address": null,
        "submit": null,
        "terms_of_service_acceptance": null
      },
      "customer": null,
      "customer_creation": "if_required",
      "customer_details": {
        "address": {
          "city": null,
          "country": "PN",
          "line1": null,
          "line2": null,
          "postal_code": null,
          "state": null
        },
        "email": "email",
        "name": "name",
        "phone": null,
        "tax_exempt": "none",
        "tax_ids": [
        ]
      },
      "customer_email": null,
      "expires_at": 1720533984,
      "invoice": null,
      "invoice_creation": {
        "enabled": false,
        "invoice_data": {
          "account_tax_ids": null,
          "custom_fields": null,
          "description": null,
          "footer": null,
          "issuer": null,
          "metadata": {
          },
          "rendering_options": null
        }
      },
      "livemode": false,
      "locale": null,
      "metadata": {
        "user": "user_who_loged"
      },
      "mode": "payment",
      "payment_intent": "pi_3PaIDLGKlfpQfnx918HiVozd",
      "payment_link": null,
      "payment_method_collection": "if_required",
      "payment_method_configuration_details": {
        "id": "pmc_1PY9NLGKlfpQfnx9LdBoV5BK",
        "parent": null
      },
      "payment_method_options": {
        "card": {
          "request_three_d_secure": "automatic"
        }
      },
      "payment_method_types": [
        "card",
        "link"
      ],
      "payment_status": "paid",
      "phone_number_collection": {
        "enabled": false
      },
      "recovered_from": null,
      "saved_payment_method_options": 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": "{url_website}/?success=true&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": 1,
  "request": {
    "id": null,
    "idempotency_key": null
  },
  "type": "checkout.session.completed"
}

服务器日志输出

Payload

b'{\n  "id": "evt_1PaLctGKlfpQfnx9CVEMf0LE",\n  "object": "event",\n  "api_version": "2024-06-20",\n  "created": 1720460723,\n  "data": {\n    "object": {\n      "id": "cs_test_a1W2LUKRDeLyo3fwTaoVpxA1oaBbQ8Bdwe4KKPTX0F7gGg4LSCg9BoAxJk",\n      "object": "checkout.session",\n      "after_expiration": null,\n      "allow_promotion_codes": null,\n      "amount_subtotal": 500,\n      "amount_total": 500,\n      "automatic_tax": {\n        "enabled": false,\n        "liability": null,\n        "status": null\n      },\n      "billing_address_collection": null,\n      "cancel_url": "{url_server}/?canceled=true",\n      "client_reference_id": null,\n      "client_secret": null,\n      "consent": null,\n      "consent_collection": null,\n      "created": 1720460707,\n      "currency": "usd",\n      "currency_conversion": null,\n      "custom_fields": [\n\n      ],\n      "custom_text": {\n        "after_submit": null,\n        "shipping_address": null,\n        "submit": null,\n        "terms_of_service_acceptance": null\n      },\n      "customer": null,\n      "customer_creation": "if_required",\n      "customer_details": {\n        "address": {\n          "city": null,\n          "country": "QA",\n          "line1": null,\n          "line2": null,\n          "postal_code": null,\n          "state": null\n        },\n        "email": "email",\n        "name": "name",\n        "phone": null,\n        "tax_exempt": "none",\n        "tax_ids": [\n\n        ]\n      },\n      "customer_email": null,\n      "expires_at": 1720547107,\n      "invoice": null,\n      "invoice_creation": {\n        "enabled": false,\n        "invoice_data": {\n          "account_tax_ids": null,\n          "custom_fields": null,\n          "description": null,\n          "footer": null,\n          "issuer": null,\n          "metadata": {\n          },\n          "rendering_options": null\n        }\n      },\n      "livemode": false,\n      "locale": null,\n      "metadata": {\n        "user": "user_who_logged"\n      },\n      "mode": "payment",\n      "payment_intent": "pi_3PaLcrGKlfpQfnx91DXMhSXB",\n      "payment_link": null,\n      "payment_method_collection": "if_required",\n      "payment_method_configuration_details": {\n        "id": "pmc_1PY9NLGKlfpQfnx9LdBoV5BK",\n        "parent": null\n      },\n      "payment_method_options": {\n        "card": {\n          "request_three_d_secure": "automatic"\n        }\n      },\n      "payment_method_types": [\n        "card",\n        "link"\n      ],\n      "payment_status": "paid",\n      "phone_number_collection": {\n        "enabled": false\n      },\n      "recovered_from": null,\n      "saved_payment_method_options": null,\n      "setup_intent": null,\n      "shipping_address_collection": null,\n      "shipping_cost": null,\n      "shipping_details": null,\n      "shipping_options": [\n\n      ],\n      "status": "complete",\n      "submit_type": null,\n      "subscription": null,\n      "success_url": "{web_server}/?success=true\\u0026session_id={CHECKOUT_SESSION_ID}",\n      "total_details": {\n        "amount_discount": 0,\n        "amount_shipping": 0,\n        "amount_tax": 0\n      },\n      "ui_mode": "hosted",\n      "url": null\n    }\n  },\n  "livemode": false,\n  "pending_webhooks": 3,\n  "request": {\n    "id": null,\n    "idempotency_key": null\n  },\n  "type": "checkout.session.completed"\n}'

Sig Header

t=1720460723,v1=633e50ecd694f51fc6ee2b38586304cd3d73575b2958a1863c5e4ca0854b00b8,v0=a82427ef23faaf0a8d6e5b6b6e466263379fe6f835e8bcd99bd6cde4d4bcb138

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:35:57