text/eventstream
, 可以持續(xù)向客戶端發(fā)送數(shù)據(jù), 使用webman作為服務(wù)端應(yīng)當(dāng)如何實現(xiàn)?客戶端如下:
const eventSource = new EventSource("http://example.cc/api/test");
eventSource.onmessage = function (e) {
console.log(e);
};
參考下面代碼
app/controller/StreamController.php
<?php
namespace app\controller;
use support\Request;
use support\Response;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\ServerSentEvents;
use Workerman\Timer;
class StreamController
{
public function index(Request $request): Response
{
$connection = $request->connection;
$id = Timer::add(1, function () use ($connection, &$id) {
// 連接關(guān)閉時,清除定時器
if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
Timer::del($id);
}
$connection->send(new ServerSentEvents(['data' => 'hello']));
});
return response('', 200, [
'Content-Type' => 'text/event-stream',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
]);
}
}
js
var source = new EventSource('http://127.0.0.1:8787/stream');
source.addEventListener('message', function (event) {
var data = event.data;
console.log(data); // 輸出 hello
}, false)
創(chuàng)建 process/EventSource.php
<?php
namespace process;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\ServerSentEvents;
use Workerman\Protocols\Http\Response;
use Workerman\Timer;
class EventSource
{
public function onMessage(TcpConnection $connection, Request $request)
{
// 如果Accept頭是text/event-stream則說明是SSE請求
if ($request->header('accept') === 'text/event-stream') {
// 首先發(fā)送一個 Content-Type: text/event-stream 頭的響應(yīng)
$connection->send(new Response(200, ['Content-Type' => 'text/event-stream']));
// 定時向客戶端推送數(shù)據(jù)
$timer_id = Timer::add(2, function () use ($connection, &$timer_id){
// 連接關(guān)閉的時候要將定時器刪除,避免定時器不斷累積導(dǎo)致內(nèi)存泄漏
if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
Timer::del($timer_id);
return;
}
// 發(fā)送message事件,事件攜帶的數(shù)據(jù)為hello,消息id可以不傳
$connection->send(new ServerSentEvents(['event' => 'message', 'data' => 'hello', 'id'=>1]));
});
return;
}
$connection->send('ok');
}
}
config/process.php 加入配置
return [
// ... 其它配置 ...
'event-source' => [
'listen' => 'http://0.0.0.0:8686',
'handler' => \process\EventSource::class,
]
];
前端測試代碼
var source = new EventSource('http://127.0.0.1:8686');
source.addEventListener('message', function (event) {
var data = event.data;
console.log(data); // 輸出 hello
}, false);
持續(xù)向瀏覽器輸出也可以使用http chunk,參考 http://wtbis.cn/q/10071 。
當(dāng)然也可以用 webman/push 插件利用 websocket 持續(xù)向瀏覽器推送數(shù)據(jù)
http://wtbis.cn/doc/workerman/http/response.html#%E5%8F%91%E9%80%81http%20chunk%E6%95%B0%E6%8D%AE
http://wtbis.cn/doc/workerman/http/SSE.html