如何使用webman创建一个text/eventstream响应, 使服务端持续向客户端发送数据

伯符

问题描述

如题, 最近看到一个Content-type类型:text/eventstream, 可以持续向客户端发送数据, 使用webman作为服务端应当如何实现?

客户端如下:

  const eventSource = new EventSource("http://example.cc/api/test");
  eventSource.onmessage = function (e) {
    console.log(e);
  };
2383 2 15
2个回答

北月

可以参考这个包 hhxsv5/php-sse
需要自己保存链接,配合定时器就可以持续的向客户端发送数据了。

  • juns 2023-04-03

    大大,如何在Controller里保存使用TcpConnection

walkor

一个请求多个响应的这种需要用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');
    }
}

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);

其它方案

持续向浏览器输出也可以使用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

  • 10bang 2023-03-17

  • xiangxihenli 2023-04-11

    这么一看是不是不支持路由和中间件了,逻辑都要在OnMessage里面重新实现一遍了吧

年代过于久远,无法发表回答
🔝