Razor Pay支付成功但未调用callback_url问题求助
核心问题1:callback_url未触发的原因
你配置了前端handler函数,Razorpay的默认逻辑是优先执行前端handler,而非触发callback_url的跳转/回调。只要存在handler,Razorpay就会跳过callback_url的自动调用。
核心问题2:添加redirect:true后支付失败的常见原因
1. callback_url不是绝对URL
Razorpay要求callback_url必须是完整的http/https开头的绝对地址,你用{% url 'PaymentSuccess' %}生成的是相对路径(比如/payment-success/),Razorpay服务器无法解析这个相对路径,导致回调失败,进而触发支付失败。
2. 后端视图未配置正确的请求方法或CSRF豁免
Razorpay的callback是POST请求,且不会携带Django的CSRF Token。如果你的PaymentSuccess视图没有开启POST支持,或者没有添加@csrf_exempt装饰器,Django会直接拦截请求,返回403 Forbidden,导致Razorpay判定支付失败。
3. 签名验证缺失(隐性问题)
即使callback_url触发,若未验证Razorpay的签名,业务逻辑会存在安全风险,同时部分场景下Razorpay会因为回调处理异常判定失败。
具体修复步骤
步骤1:修正callback_url为绝对URL
在Django模板中,使用request.build_absolute_uri生成完整URL:
var options = { "key": data.razorpay_key, "amount": data.amount, "currency": data.currency, "name": "BusinessCard4U", "image": "{{websitelogo.image.url}}", "description": "Payment for digital card subscription", "order_id": data.razorpay_order_id, // 替换为绝对URL "callback_url": "{{ request.build_absolute_uri|add:payment_success_path }}", // 若依赖callback_url自动跳转,移除handler函数 // "handler": function (response){...}, "theme": { "color": "#5EB9F0" }, };
注:如果保留handler,需要在handler中手动跳转,但必须先完成签名验证
步骤2:修复后端视图配置
给PaymentSuccess视图添加POST支持和CSRF豁免,并实现签名验证:
from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse, HttpResponseMethodNotAllowed import hmac import hashlib @csrf_exempt def PaymentSuccess(request): if request.method != 'POST': return HttpResponseMethodNotAllowed(['POST']) # 从请求中获取Razorpay返回的参数 razorpay_order_id = request.POST.get('razorpay_order_id') razorpay_payment_id = request.POST.get('razorpay_payment_id') razorpay_signature = request.POST.get('razorpay_signature') # 验证签名(必须步骤,防止伪造请求) secret_key = b'YOUR_RAZORPAY_SECRET_KEY' # 替换为你的密钥 message = f"{razorpay_order_id}|{razorpay_payment_id}".encode() generated_signature = hmac.new(secret_key, message, hashlib.sha256).hexdigest() if generated_signature == razorpay_signature: # 签名验证通过,处理你的业务逻辑(比如更新订单状态) return HttpResponse("Payment Verified Successfully") else: # 签名验证失败,拒绝处理 return HttpResponse("Invalid Payment Signature", status=400)
步骤3:调整handler与callback_url的逻辑
- 如果依赖自动跳转:移除
handler函数,添加redirect: true参数,此时Razorpay会在支付成功后自动跳转到callback_url。 - 如果需要保留前端handler:在handler中完成签名验证后,手动跳转到后端接口:
"handler": function (response){ // 先验证签名(前端验证仅作辅助,必须后端再次验证) var orderId = response.razorpay_order_id; var paymentId = response.razorpay_payment_id; var signature = response.razorpay_signature; // 调用后端接口验证签名,验证通过后跳转 fetch('/verify-signature/', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ order_id: orderId, payment_id: paymentId, signature: signature }) }).then(res => res.json()) .then(data => { if(data.success){ window.location.href = "{{ request.build_absolute_uri|add:payment_success_path }}"; } }); },
步骤4:查看Razorpay后台日志定位问题
如果仍然失败,登录Razorpay后台,找到对应订单的失败详情,里面会明确标注回调失败的原因(比如403、404、500等),根据错误码进一步排查。
内容的提问来源于stack exchange,提问作者Proud

