Django+Stripe支付success_url本地正常生产环境报400错误求助
Django + Stripe 生产环境支付成功页返回400 Bad Request错误
问题描述
本地环境下集成Stripe支付的Django网站功能正常,支付成功后能正常跳转至order_complete页面并加载会话数据,但部署到AWS Elastic Beanstalk后,支付成功页返回**Bad Request(400)**错误。Webhook已正确配置并能捕获所有Stripe事件,仅成功页加载失败。
相关代码
charges视图(生成Stripe会话)
def charges(request, order_id): try: cart_items = CartItem.objects.filter(user=request.user) domain = settings.DOMAIN_NAME if settings.DEBUG: domain = "http://127.0.0.1:8000/" session = stripe.checkout.Session.create( customer_email=request.user.email, payment_method_types=['card'], line_items=[{ 'price_data': { 'product_data': { 'name': cart_item.product.product_name, }, 'unit_amount_decimal': cart_item.product.price*100, 'currency': 'usd', }, 'quantity': cart_item.quantity, 'tax_rates': [tax_rate.id], } for cart_item in cart_items], metadata={ "orderID": order_id }, mode='payment', success_url=domain + 'orders/order_complete?session_id={CHECKOUT_SESSION_ID}', cancel_url=domain + 'orders/order_incomplete?session_id={CHECKOUT_SESSION_ID}', ) # Pass the session ID to the template return JsonResponse({ "id": session.id }) except stripe.error.InvalidRequestError as e: # Handle the specific InvalidRequestError exception print(f"Invalid request error: {e.param}") except stripe.error.StripeError as e: # Handle other Stripe-related errors print(f"Stripe error: {e}") except stripe.error.ValueError as e: print(f"Stripe error: {e}") except Exception as e: # Handle other general exceptions return JsonResponse({'error': str(e)})
order_complete视图(渲染成功页)
def order_complete(request): session_id = request.GET.get('session_id') session = stripe.checkout.Session.retrieve(session_id) order_number = session["metadata"]["orderID"] transID = session["id"] try: order = Order.objects.get(order_number=order_number, is_ordered=True) ordered_products = OrderProduct.objects.filter(order_id=order.id) payment = Payment.objects.get(payment_id=transID) context = { 'order': order, 'ordered_products': ordered_products, 'order_number': order.order_number, 'transID': payment.payment_id, 'payment': payment, } return render(request, "orders/order_complete.html", context) except (Payment.DoesNotExist, Order.DoesNotExist): return redirect('home')
order_complete.html模板
{% block content %} <div class="container" style="margin-top: 50px; text-align:center"> <i class="fas fa-check-circle" style="font-size: 72px;margin-bottom: 20px;color: #28A745;"></i> <h2 class="text-center">Payment Successful</h2> <br> <div class="text-center"> <a href="{% url 'store' %}" class="btn btn-success">Shop more</a> </div> </div> <div class="container" style="margin: 0 auto;width: 50%;padding: 50px;background: #f1f1f1;margin-top: 50px;margin-bottom: 50px;"> <div class="row invoice row-printable"> <div class="col-md-12"> <!-- col-lg-12 start here --> <div class="panel panel-default plain" id="dash_0"> <!-- Start .panel --> <div class="panel-body p30"> <div class="row"> <!-- Start .row --> <div class="col-lg-6"> <!-- col-lg-6 start here --> <div class="invoice-logo"><img src="{% static '/images/logo.png' %}" alt="Invoice logo" style="max-height: 40px;"></div> </div> <!-- col-lg-6 end here --> <div class="col-lg-6"> <!-- col-lg-6 start here --> <div class="invoice-from"> <ul class="list-unstyled text-right"> <li><strong>Invoiced To</strong></li> <li>{{order.full_name}}</li> <li>{{order.full_address}}</li> <li>{{order.city}}, {{order.state}} {{order.zip}}</li> </ul> </div> </div> <!-- col-lg-6 end here --> <div class="col-lg-12"> <!-- col-lg-12 start here --> <div class="invoice-details mt25"> <div class="well"> <ul class="list-unstyled mb0"> <li><strong>Order:</strong> #{{order_number}}</li> <li><strong>Transaction ID:</strong> {{transID}}</li> <li><strong>Order Date:</strong> {{order.created_at}}</li> <li><strong>Status:</strong> {{order.status}}</li> </ul> </div> </div> <div class="invoice-items"> <div class="table-responsive" style="overflow: hidden; outline: none;" tabindex="0"> <table class="table table-bordered"> <thead> <tr> <th class="per70 text-center">Products</th> <th class="per5 text-center">Qty</th> <th class="per25 text-center">Total</th> </tr> </thead> <tbody> {% for item in ordered_products %} <tr> <td>{{item.product.product_name}} <p class="text-muted small"> {% if item.variations.all %} {% for i in item.variations.all %} {{ i.variation_category | capfirst }} : {{ i.variation_value | capfirst }} <br> {% endfor %} {% endif %} </p> </td> <td class="text-center">{{item.quantity}}</td> <td class="text-center">${{item.product_price}}</td> </tr> {% endfor %} </tbody> <tfoot> <tr> <th colspan="2" class="text-right">Sub Total:</th> <th class="text-center">${{order.sub_total}} </th> </tr> <tr> <th colspan="2" class="text-right">Tax:</th> <th class="text-center">${{order.tax}} </th> </tr> <tr> <th colspan="2" class="text-right">Order Total:</th> <th class="text-center">${{order.order_total}} </th> </tr> </tfoot> </table> </div> </div> <div class="invoice-footer mt25"> <p class="text-center">Thank you for shopping with us!</p> </div> </div> <!-- col-lg-12 end here --> </div> <!-- End .row --> </div> </div> <!-- End .panel --> </div> <!-- col-lg-12 end here --> </div> </div> {% endblock content %}
排查方向与解决方案
1. 生产环境DOMAIN_NAME配置问题
- 检查
settings.DOMAIN_NAME是否包含正确的HTTPS协议前缀,生产环境必须使用HTTPS,否则Stripe跳转时会出现协议不匹配的请求错误。 - 确保
DOMAIN_NAME末尾无多余斜杠,避免生成的success_url出现//orders/...的格式错误。
2. Stripe密钥与会话参数验证
- 确认生产环境使用的是Stripe生产密钥,而非测试密钥,否则
stripe.checkout.Session.retrieve(session_id)会因权限问题抛出异常。 - 在
order_complete视图中添加日志打印session_id,验证Stripe跳转时参数是否完整传递。
3. Django安全设置拦截
- 虽然
order_complete是GET请求,但生产环境中Django的SECURE_BROWSER_XSS_FILTER等安全设置可能拦截请求,可临时添加@csrf_exempt装饰器测试是否解决问题,后续再调整CSRF白名单确保安全。
4. AWS Elastic Beanstalk环境配置
- 检查Elastic Beanstalk负载均衡器是否配置了有效HTTPS证书,确保请求能正常转发到Django应用。
- 确认Elastic Beanstalk环境变量中正确设置了Stripe生产密钥和
DOMAIN_NAME,避免配置缺失导致的错误。
5. 订单状态同步延迟
- Webhook捕获事件后可能存在数据库写入延迟,导致
order_complete视图查询时Order或Payment记录尚未创建。可在视图中添加重试逻辑,或在Webhook处理函数中确保订单状态更新完成后再允许访问成功页。
内容的提问来源于stack exchange,提问作者MasDev
相关产品推荐
相关产品推荐

