<?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) {
// 连接关闭时,清除定时器
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)
Webman 自定义进程方式
创建 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') {
// 首先发送一个 Content-Type: text/event-stream 头的响应
$connection->send(new Response(200, ['Content-Type' => 'text/event-stream']));
// 定时向客户端推送数据
$timer_id = Timer::add(2, function () use ($connection, &$timer_id){
// 连接关闭的时候要将定时器删除,避免定时器不断累积导致内存泄漏
if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
Timer::del($timer_id);
return;
}
// 发送message事件,事件携带的数据为hello,消息id可以不传
$connection->send(new ServerSentEvents(['event' => 'message', 'data' => 'hello', 'id'=>1]));
});
return;
}
$connection->send('ok');
}
}
var source = new EventSource('http://127.0.0.1:8686');
source.addEventListener('message', function (event) {
var data = event.data;
console.log(data); // 输出 hello
}, false);
Webman控制器方式
参考下面代码
app/controller/StreamController.php
js
Webman 自定义进程方式
创建 process/EventSource.php
config/process.php 加入配置
前端测试代码
其它方案
持续向浏览器输出也可以使用http chunk,参考 https://www.workerman.net/q/10071 。
当然也可以用 webman/push 插件利用 websocket 持续向浏览器推送数据
相关文档
https://www.workerman.net/doc/workerman/http/response.html#%E5%8F%91%E9%80%81http%20chunk%E6%95%B0%E6%8D%AE
https://www.workerman.net/doc/workerman/http/SSE.html
赞
这么一看是不是不支持路由和中间件了,逻辑都要在OnMessage里面重新实现一遍了吧