Laravel 8中Razorpay Webhook集成指南及空数据问题排查
Laravel 8 集成 Razorpay Webhook 完整指南及问题排查
一、分步集成指南
1. 安装 Razorpay SDK
通过Composer安装官方SDK:
composer require razorpay/razorpay
2. 配置环境变量
在.env文件中添加Razorpay密钥及Webhook密钥:
RAZORPAY_KEY=your_key_here RAZORPAY_SECRET=your_secret_here RAZORPAY_WEBHOOK_SECRET=your_webhook_secret_here
3. 配置路由
在routes/api.php中添加Webhook接收路由:
Route::post('/razorpay/webhook', [App\Http\Controllers\RazorpayWebhookController::class, 'handle']);
关键:排除CSRF验证
Webhook请求来自外部,需跳过Laravel的CSRF检查。修改app/Http/Middleware/VerifyCsrfToken.php:
protected $except = [ '/api/razorpay/webhook', ];
4. 创建Webhook控制器
生成控制器并编写核心处理逻辑:
php artisan make:controller RazorpayWebhookController
控制器代码示例:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Razorpay\Api\Api; use Razorpay\Api\Errors\SignatureVerificationError; class RazorpayWebhookController extends Controller { public function handle(Request $request) { $api = new Api(env('RAZORPAY_KEY'), env('RAZORPAY_SECRET')); $webhookSecret = env('RAZORPAY_WEBHOOK_SECRET'); try { // 验证Webhook签名,防止伪造请求 $api->utility->verifyWebhookSignature( $request->getContent(), $request->header('X-Razorpay-Signature'), $webhookSecret ); } catch (SignatureVerificationError $e) { \Log::error('Razorpay Webhook签名验证失败: ' . $e->getMessage()); return response()->json(['status' => 'error'], 400); } // 获取Webhook payload $payload = $request->json()->all(); $event = $payload['event']; // 根据不同事件处理业务逻辑 switch ($event) { case 'payment.captured': $payment = $payload['payload']['payment']['entity']; // 示例:更新订单状态、发送支付成功通知 \Log::info('支付成功,Payment ID: ' . $payment['id']); break; case 'payment.failed': $payment = $payload['payload']['payment']['entity']; // 示例:标记订单失败、通知用户 \Log::info('支付失败,Payment ID: ' . $payment['id']); break; // 可按需添加其他事件(如refund.processed)的处理逻辑 default: \Log::info('未处理的Webhook事件: ' . $event); } // 返回成功响应,告知Razorpay无需重试 return response()->json(['status' => 'success'], 200); } }
二、最佳实践
- 强制签名验证:绝不能跳过签名验证,这是拦截伪造请求的核心防线,直接使用SDK提供的验证方法即可。
- 异步处理业务逻辑:Webhook要求10秒内响应,将订单更新、通知发送等耗时操作放入队列:
// 替换同步逻辑为队列任务 dispatch(new ProcessRazorpayPayment($payment)); - 完善日志记录:记录所有Webhook请求的原始payload、签名、处理结果,方便事后排查问题。
- 保证幂等性:同一事件可能被Razorpay多次推送,需通过
event_id或payment_id标记已处理事件,避免重复执行:if (WebhookLog::where('event_id', $payload['event_id'])->exists()) { return response()->json(['status' => 'already processed'], 200); } // 先记录日志再处理业务 WebhookLog::create(['event_id' => $payload['event_id'], 'payload' => $payload]); - 正确返回响应码:处理成功返回
200 OK,验证失败返回400 Bad Request,服务器错误返回500 Internal Server Error,Razorpay会对非200响应进行重试。
三、接收数据为空的排查步骤
- 检查CSRF拦截:确认Webhook路由已添加到
VerifyCsrfToken的$except数组中,否则Laravel会直接拒绝请求,导致无法获取数据。 - 确认请求解析方式:Razorpay发送的是
application/json格式请求,若使用web路由而非api路由,需手动解析原始内容:$payload = json_decode($request->getContent(), true); - 排查服务器配置:检查Nginx/Apache是否拦截请求,比如ModSecurity模块可能误判Webhook请求为恶意请求,需添加放行规则。
- 本地测试验证:使用ngrok将本地服务暴露到公网,在Razorpay后台配置测试URL,触发测试事件后查看Laravel日志中的请求详情。
- 检查数据获取代码:优先使用
$request->json()->all()或json_decode($request->getContent(), true)获取原始JSON数据,避免直接用$request->all()。 - 验证Webhook URL正确性:确认Razorpay后台配置的URL与本地路由完全一致,包括协议(http/https)、路径等。
内容的提问来源于stack exchange,提问作者Vaibhav Yadav
相关产品推荐
相关产品推荐

