Stripe Dashboard显示400但CLI返回200的Django Webhook问题
Stripe Webhook:CLI显示200但Dashboard显示400的疑问
为了做sanity check,我们在Django应用的Stripe Webhook中直接返回200状态码。从截图可见:
- Stripe CLI显示事件正常接收,且返回了200状态码
- 但Stripe Dashboard中对应事件却显示状态码400
想咨询:如果CLI能正常接收响应,Dashboard里的状态是否会产生实际影响?
测试用Webhook代码
@method_decorator(csrf_exempt, name='dispatch') class StripeWebhook(APIView): def post(self, request, *args, **kwargs): return HttpResponse({status: "success"},status=200) # 以下是正常业务逻辑,当前仅做sanity check验证Dashboard是否能识别200 print('received payment. in webhook') stripe.api_key = settings.STRIPE_TEST_SECRET event = None payload = request.body sig_header = request.META["HTTP_STRIPE_SIGNATURE"] try: event = stripe.Webhook.construct_event( payload, sig_header, 'settings.WEBHOOK_SECRET' ) except ValueError as e: print("aaa") print(e) return HttpResponse(status=400) except stripe.error.SignatureVerificationError as e: print('bbb') print(e) return HttpResponse(status=400) if event['type'] == 'checkout.session.completed': print('payment success') elif event['type'] == 'payment_intent.payment_failed': # 处理支付失败事件 print('payment failed') return HttpResponse('something went wrong', status=400) return HttpResponse({'status': 'success'})
相关截图
- Stripe CLI日志:

- Stripe Dashboard事件状态:

解答
1. Dashboard状态的实际影响
- 仅用Stripe CLI做本地开发测试:Dashboard的状态不会影响本地测试流程,因为CLI是将Stripe事件转发到你的本地服务,和Stripe服务器直接请求你的公网Webhook地址是两条独立路径。
- 需要Stripe服务器直接向线上/测试环境地址发送事件:Dashboard的400状态说明Stripe服务器请求你的Webhook地址时收到了错误响应,这会导致Stripe重试未成功的事件(最多重试3天),如果一直失败,可能会影响业务逻辑(比如支付成功事件未被处理,无法更新订单状态)。
2. 为什么CLI显示200但Dashboard显示400?
核心原因是两者的请求环境和验证逻辑不同:
- CLI转发的是本地请求:你的本地服务能正常响应200,但公网Webhook地址可能存在问题(比如无法被公网访问、签名验证失败、响应格式不符合要求)。
- 代码响应格式错误:测试代码里
return HttpResponse({status: "success"},status=200)有两个问题:status未加引号,生成的内容不是有效的JSON(Stripe要求Webhook响应最好是JSON格式,至少是合法的HTTP响应内容)- Django的
HttpResponse不会自动将字典序列化为JSON,应该用JsonResponse({"status": "success"}, status=200),否则返回的内容可能被Stripe判定为无效,从而标记为400。
- Webhook配置不一致:Dashboard中配置的Webhook地址、签名密钥可能和CLI使用的不一致,导致Stripe服务器请求时验证失败返回400。
3. 修复建议
- 修正响应格式:将测试代码中的返回语句改为
return JsonResponse({"status": "success"}, status=200)(需导入from django.http import JsonResponse)。 - 验证公网地址可达性:确保Webhook地址能被公网访问,且签名密钥配置正确(不要用字符串
'settings.WEBHOOK_SECRET',应直接引用settings.WEBHOOK_SECRET)。 - 查看Dashboard事件详情:点击400状态的事件,查看具体错误信息(比如“Invalid signature”“Connection error”等),针对性修复。
内容的提问来源于stack exchange,提问作者asadimran___
相关产品推荐
相关产品推荐

