无mod rewrite的Yii应用SendGrid事件Webhook无法携带GET参数问题
问题解决:SendGrid Event Webhook 适配无mod rewrite的Yii应用
核心结论
SendGrid的Event Webhook不会保留URL中的GET查询参数,它只会将事件数据以POST请求方式发送,原URL里的?r=...这类参数会被忽略——这就是你配置https://example.com/?r=sendgrid/action后没收到请求的核心原因(SendGrid实际请求的是不带查询参数的地址,Yii无法识别路由)。
解决方案
方法1:新增独立的Webhook接收脚本
在网站根目录创建单独的PHP文件(比如sendgrid-webhook.php),直接在脚本里初始化Yii并调用目标控制器动作:
<?php // 引入Yii配置和入口逻辑(路径根据你的项目结构调整) require_once(__DIR__ . '/protected/config/main.php'); // 直接调用指定控制器的动作 Yii::createWebApplication($config)->runController('sendgrid/action');
随后把SendGrid的Webhook配置为https://example.com/sendgrid-webhook.php即可,SendGrid发送的POST请求会触发这个脚本,进而调用你的Yii控制器处理事件。
方法2:修改Yii入口文件适配路由
如果不想新增脚本,可以修改根目录的index.php,判断是否为SendGrid的请求,强制指定路由参数:
<?php $config = __DIR__ . '/protected/config/main.php'; // 通过请求头识别SendGrid的Webhook请求 $isSendGridHook = isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'SendGrid') !== false; if ($isSendGridHook) { // 强制设置Yii路由参数 $_GET['r'] = 'sendgrid/action'; } Yii::createWebApplication($config)->run();
之后把SendGrid的Webhook配置为https://example.com/index.php即可,请求会被Yii正确路由到目标控制器。
额外建议:验证请求合法性
为避免恶意请求,建议在控制器的处理动作里添加SendGrid请求签名验证:
public function actionAction() { $signature = $_SERVER['HTTP_X_TWILIO_EMAIL_EVENT_WEBHOOK_SIGNATURE'] ?? ''; $timestamp = $_SERVER['HTTP_X_TWILIO_EMAIL_EVENT_WEBHOOK_TIMESTAMP'] ?? ''; $payload = file_get_contents('php://input'); $secret = '你的SendGrid签名密钥'; // 从SendGrid后台获取 // 验证签名 $expectedSignature = hash_hmac('sha256', $timestamp . $payload, $secret); if (!hash_equals($expectedSignature, $signature)) { http_response_code(403); exit('Invalid request'); } // 处理事件数据 $events = json_decode($payload, true); // 你的业务逻辑代码 }
内容的提问来源于stack exchange,提问作者Denis Chenu
相关产品推荐
相关产品推荐

