Django集成Stripe支付遇Webhook签名缺失及邮件未发送问题求助
Django Stripe支付问题排查方案
一、Webhook "Missing stripe signature" 错误排查
- 验证签名密钥与请求头获取方式
- 确保使用Stripe控制台生成的Webhook专属签名密钥(格式为
whsec_xxx),而非普通API密钥 - Django中需从
request.META.get('HTTP_STRIPE_SIGNATURE')获取签名头,注意是大写前缀HTTP_,不能直接用request.headers.get('Stripe-Signature')(部分WSGI服务器会转换头格式)
- 确保使用Stripe控制台生成的Webhook专属签名密钥(格式为
- 必须使用原始请求体验证
- 禁止使用
request.POST或request.data(Django会自动解析请求体,破坏签名验证的原始数据),直接读取request.body作为payload传入stripe.Webhook.construct_event
- 禁止使用
- 调整时间窗口(可选)
- 若请求存在延迟,可在
construct_event中增加tolerance参数放宽时间限制,例如tolerance=600(10分钟)
- 若请求存在延迟,可在
- 确认端点配置
- 检查Stripe控制台中Webhook端点URL与本地/线上部署的URL完全一致,本地开发需用ngrok等工具暴露公网可访问的地址
正确Webhook视图示例:
import stripe from django.http import HttpResponse from django.views.decorators.http import require_POST stripe.api_key = "你的Stripe API密钥" WEBHOOK_SECRET = "你的Webhook签名密钥" @require_POST def stripe_webhook(request): payload = request.body sig_header = request.META.get('HTTP_STRIPE_SIGNATURE') event = None try: event = stripe.Webhook.construct_event( payload, sig_header, WEBHOOK_SECRET # 可选:放宽时间限制 # tolerance=600 ) except ValueError: return HttpResponse(status=400) except stripe.error.SignatureVerificationError: return HttpResponse(status=400) # 绑定业务逻辑 if event['type'] == 'checkout.session.completed': handle_checkout_session(event['data']['object']) return HttpResponse(status=200)
二、handle_checkout_session未发送邮件排查
- 确认函数是否被触发
- 在函数开头添加日志输出,例如用Django logger或print语句,查看是否有执行记录
- 登录Stripe控制台查看Webhook事件日志,确认
checkout.session.completed事件已成功送达你的端点,且返回200状态码
- 检查邮件配置与代码
- 验证
settings.py中的邮件配置是否正确(EMAIL_HOST、EMAIL_PORT、EMAIL_HOST_USER、EMAIL_HOST_PASSWORD等),可先测试发送一封测试邮件确认配置有效 - 移除
send_mail中的fail_silently=True,强制抛出异常,排查是否有邮件发送错误被静默吞掉 - 确认从checkout session中获取的收件邮箱(如
session['customer_email'])不为空,避免因无收件人导致邮件不发送
- 验证
排查用handle_checkout_session示例:
import logging from django.core.mail import send_mail logger = logging.getLogger(__name__) def handle_checkout_session(session): logger.debug("开始处理支付会话: %s", session.id) customer_email = session.get('customer_email') if not customer_email: logger.error("支付会话%s未获取到用户邮箱", session.id) return try: send_mail( '支付成功通知', '你的订单已完成支付,感谢支持!', 'noreply@yourdomain.com', [customer_email], fail_silently=False, # 关闭静默失败,抛出异常便于排查 ) logger.info("支付通知邮件已发送至: %s", customer_email) except Exception as e: logger.error("发送邮件失败: %s", str(e)) raise # 抛出异常,避免静默失败导致无法发现问题
内容的提问来源于stack exchange,提问作者Yekpahi Prince
相关产品推荐
相关产品推荐

