You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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数据:

  1. 单独创建Webhook端点,接收POST请求并将数据写入中间存储;
  2. 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>

验证步骤

  1. 启动PHP服务,确保sse2.php和webhook.php可访问;
  2. 打开客户端页面,确认收到connected事件;
  3. 用Postman或curl向webhook.php发送POST请求,例如:
    curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' http://localhost/webhook.php
    
  4. 客户端页面应立即收到Webhook推送的事件数据。

内容的提问来源于stack exchange,提问作者Melvis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:35:07