关于walkor给的SSE示例,为什么收不到建立连接后的第一条消息呢?

Jedi

服务端给消息里加个时间
截图
客户端里可见本次消息时间和上次消息时间
截图
消息打印结果如图
截图
客户打印出来的第一条消息里lastEventId输出的时间与服务器发送的第一条消息的时间相同,也就是说客户端只打印了服务器发送过来的第二条消息,嗯。。。我有点整不明白了

655 3 0
3个回答

damao
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\ServerSentEvents;
use Workerman\Protocols\Http\Response;
use Workerman\Timer;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8080');

$worker->onMessage = function(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){
            static $id = 0;
            // 连接关闭的时候要将定时器删除,避免定时器不断累积导致内存泄漏
            if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
                Timer::del($timer_id);
                return;
            }
            // 发送message事件,事件携带的数据为hello,消息id可以不传
            $connection->send(new ServerSentEvents(['event' => 'message', 'data' => 'hello', 'id'=>$id++]));
        });
        return;
    }
    $connection->send("<script>
var source = new EventSource('http://127.0.0.1:8080');
source.addEventListener('message', function (event) {
  var data = event.data;
  console.log(event); // 输出 hello
}, false);
</script>");
};

// 运行worker
Worker::runAll();

截图
id从0开始输出的,没问题

  • Jedi 2023-03-24

    这个id对应的是event.lastEventId,但lastEvent客户端并没有收到,比如改成这样比对一下服务端发送的内容和客户端打印出的内容

  • Jedi 2023-03-24

    $timer_id = Timer::add(2, function () use ($connection, &$timer_id){
    static $id = 0;
    // 连接关闭的时候要将定时器删除,避免定时器不断累积导致内存泄漏
    if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
    Timer::del($timer_id);
    return;
    }
    // 发送message事件,事件携带的数据为hello,消息id可以不传
    $data='data of event with ID '.$id;
    echo "I'm about send msgid:$id".PHP_EOL;
    $connection->send(new ServerSentEvents(['event' => 'message', 'data' => $data, 'id'=>$id]));
    $id++;
    });

小W

是不是服务端发送的数据,第一次客户端收不到;客户端第二次收到的数据中lastEventId却可以获取到服务端第一次发送的id

  • Jedi 2023-03-24

    嗯嗯
    是这样

  • 小W 2023-03-24

    你看看你的eventsource状态,在第一次发送数据后有没有变化

  • Jedi 2023-03-24

    如果只发送1次就把timer删掉的话,客户端也收不到消息

  • Jedi 2023-03-24

    console.log(event.target.readyState); 输出>>1

小W

截图
看源码,你可以先发送一个ping出去,然后再去send就可以了

  • 小W 2023-03-24

    这是我改过的[表情],哈哈哈

  • Jedi 2023-03-24

    其实就是这样发个空的消息呗
    $connection->send(new Response(200, ['Content-Type' => 'text/event-stream' , 'Access-Control-Allow-Origin' => '*']));
    $time=time();
    $connection->send(new ServerSentEvents(['data' => '', 'id'=>$time]));

  • 小W 2023-03-24

    先发一条数据,然后再定时器这样也可以

  • xiangxihenli 2023-04-11

    我发现不是没有第一条消息,而是第一条消息跟着header走了,你看看header, 讨厌没有边界的SSe data

  • 小W 2023-04-12

    哈哈哈,能用就行

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