关于(SSE: Server-Sent Events)的代码实现
本贴结合分享和问答,由问答贴 Laravel + SSE(Server-Sent Events)消息未连续发送 转化
(原帖由于问题定位不明以及多次编辑,导致逻辑有些混乱)
结论
实现:在纯 PHP 代码和 Laravel 代码都可实现;
运行:builtin-server (php -S) 可行,Nginx 可行,Apache 不正常
实现代码
前端
query();
function query() {
if (!window.EventSource) {
alert("浏览器不支持 EventSource");
return;
}
var eventSource = new EventSource("/");
eventSource.onopen = function (e) {
console.log("onEventSourceOpen")
}
eventSource.onmessage = function (e) {
console.log("onEventSourceMessage: " + e.data);
}
eventSource.onerror = function (e) {
console.log("onEventSourceError: ", e);
}
}
后端
后端代码仅在
php -S
和 Nginx 测试通过,Apache 方式暂未测试通过
PHP
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
header("Connection: keep-alive");
header("X-Accel-Buffering: no");
while (true) {
if(connection_aborted()) exit();
$ts = microtime(true);
// echo str_repeat("\n", 100000);
echo "event: message\ndata: $ts\nid: $ts\n\n";
ob_end_flush(); // 或 ob_flush()
flush();
sleep(1);
}
Laravel
// 这里加 return 或者末尾加 ->send() 都可以
return (new \Symfony\Component\HttpFoundation\StreamedResponse(function () {
while (true) {
if (connection_aborted()) return;
$ts = microtime(true);
echo str_repeat("\n", 50000);
echo "event: message\ndata: $ts $ts\nid: $ts\n\n";
// Laravel 中不加以下两个 flush 也能测试成功
ob_flush();
flush();
sleep(1);
}
}, 200, [
"Content-Type" => "text/event-stream",
"Cache-Control" => "no-cache",
"Connection" => "Keep-Alive",
"X-Accel-Buffering" => "no",
]))->send();
相关设置
builtin:直接 php -S
运行即可,注意写对 Content-Type,以及输出缓冲的刷新
Nginx:fastcgi 模式的话需要设置 fastcgi_buffering off;
,proxy 模式的话需要设置 proxy_buffering off;
(未测试);或者 php 代码设置请求头 X-Accel-Buffering: no
Apache:直接访问的话,效果是在超出 PHP 的最大执行时间之后(比如 30 秒)一次性输出很多数据;如想正常输出,可以在正常数据之前,先输出一大段空白内容(但是这个感觉是偏方,目前还没有找到能直接在代码里刷新 apache 输出缓存的方法,如有合适方法还请告知一下)
吐槽:没想到测试一个 SSE,最大的障碍是缓冲区
推荐文章: