HTTP POST请求无法触发PHP Server-Side Event问题排查
PHP Webhook触发SSE失效问题解决
问题核心
SSE端点在GET请求下可正常推送事件,但通过POST请求触发Webhook时,日志写入正常,但客户端接收不到对应的SSE事件。
根本原因
EventSource API仅支持GET请求建立持久连接。之前的错误在于混淆了两个独立的HTTP会话:Webhook的POST请求是外部服务发起的独立请求,其响应不会被客户端的EventSource实例接收;而客户端的SSE连接是另一个持续的GET请求,两者无法直接共享数据。
解决方案
通过**中间存储(文件/Redis)**中转Webhook数据:
- 单独创建Webhook端点,接收POST请求并将数据写入中间存储;
- SSE端点保持GET请求模式,持续监听中间存储的新数据,一旦有更新就推送给客户端。
修改后的代码示例
1. SSE推送端点(sse2.php)
负责持续监听消息并推送给客户端:
<?php header('Access-Control-Allow-Origin: *'); header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); // 消息存储文件路径 $messageQueue = 'sse_messages.log'; $lastReadPosition = 0; // 发送SSE事件的通用函数 function sendSSE($payload) { echo "data: " . json_encode($payload) . "\n\n"; ob_flush(); flush(); } // 发送初始连接确认 sendSSE(['status' => 'connected']); // 持续监听消息队列 while (true) { // 初始化空文件 if (!file_exists($messageQueue)) { touch($messageQueue); } $fileSize = filesize($messageQueue); // 检查是否有新消息 if ($fileSize > $lastReadPosition) { $handle = fopen($messageQueue, 'r'); fseek($handle, $lastReadPosition); // 读取所有新消息并推送 while ($message = fgets($handle)) { sendSSE([ 'type' => 'webhook', 'content' => json_decode(trim($message), true) ?: trim($message) ]); } fclose($handle); $lastReadPosition = $fileSize; } // 每隔3秒轮询一次,避免资源占用过高 sleep(3); } ?>
2. Webhook接收端点(webhook.php)
专门处理外部POST请求,将数据写入消息队列:
<?php header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST'); header('Access-Control-Allow-Headers: Content-Type'); $messageQueue = 'sse_messages.log'; $postData = file_get_contents('php://input'); if (!empty($postData)) { // 将POST数据写入消息队列 file_put_contents($messageQueue, $postData . PHP_EOL, FILE_APPEND); http_response_code(200); echo json_encode(['status' => 'success']); } else { http_response_code(400); echo json_encode(['status' => 'error', 'msg' => '无有效数据']); } ?>
3. 客户端代码(无需修改)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SSE Client</title> </head> <body> <div id="sse-data"></div> <script> const sseData = document.getElementById('sse-data'); const source = new EventSource('sse2.php'); source.onmessage = function(event) { console.log("收到SSE事件:", event); const data = JSON.parse(event.data); sseData.innerHTML += '<pre>' + JSON.stringify(data, null, 2) + '</pre>'; }; source.onerror = function(event) { console.error("EventSource连接失败:", event); }; </script> </body> </html>
验证步骤
- 启动PHP服务,确保
sse2.php和webhook.php可访问; - 打开客户端页面,确认收到
connected事件; - 用Postman或curl向
webhook.php发送POST请求,例如:curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' http://localhost/webhook.php - 客户端页面应立即收到Webhook推送的事件数据。
内容的提问来源于stack exchange,提问作者Melvis
相关产品推荐
相关产品推荐

