如何避免服务器发送事件在 Laravel 中出现单一路由

How to avoid single route in Laravel for Server Sent Events

所以我想在我的 laravel 应用程序中使用 Server Sent Events,但问题是在 SSE 中,您只能指定单个 URL,如:

var evtSource = new EventSource("sse.php");

问题是我想从整个应用程序的不同 parts/controllers 发送事件,而不仅仅是单个 sse.php 文件。示例:

// AuthController.php
public function postLogin(Request $request) {
  // login logic

  // SEND SSE EVENT ABOUT NEW USER LOGIN
}

// FooController.php
public function sendMessage() {
  // SEND SSE EVENT ABOUT NEW MESSAGE
}

我想到的唯一想法是,从这些控制器创建带有事件文本的临时文件,然后在 sse.php 文件中读取这些文本文件,发送事件,然后删除文件。然而,这看起来并不是完美的解决方案。或者可能以某种方式将 sse.php 文件与 Laravel 事件机制挂钩,但这似乎有点高级。

我也不介意使用不同的 php 文件创建多个事件源对象,例如 sse.php 但问题是这些控制器方法不一定只单独发送事件,它们还做其他工作以及。例如,我不能直接在 SSE 对象中使用 postLogin 操作,因为它还执行登录逻辑,而不仅仅是发送事件。

有没有人遇到过类似的问题,请问如何解决?

您可以使用 Laravel 的事件并创建一个侦听器,将来自您的应用程序的所有不同事件组合成一个流,然后您将拥有一个控制器来发出该流事件给客户端。您可以在代码中的任何位置生成一个事件,并将其流式传输到客户端。你需要某种共享的 FIFO 缓冲区来允许监听器和控制器之间的通信,监听器会写入它,控制器会读取它并发送 SSE。最简单的解决方案是为此使用一个普通的日志文件。

Laravel 还具有使用 Laravel Echo 的内置广播功能,所以这可能会有所帮助吗?我不确定 Echo 是否在使用 SSE(两者都为零),但它做的事情几乎相同......

更新:让我试着添加一个例子:

1) 首先我们需要创建一个事件和一个监听器,例如:

php artisan make:event SendSSE
php artisan make:listener SendSSEListener --event=SendSSE

2) 您的事件 class 只是您希望传递给侦听器的数据的包装器。根据需要向 SendSSE class 添加任意数量的属性,但对于此示例,我们只传递一条字符串消息:

    public function __construct($msg)
    {
        $this->message = $msg;
    } 

    public function getMessage()
    {
        return $this->message;
    } 

3) 现在您可以像这样触发此事件:

event(new \App\Events\SendSSE('Hello there'));

4) 您的侦听器的 handle() 方法将接收它,然后您需要将它推入您将用于与 SSE 控制器通信的 FIFO 缓冲区。这可以像写入文件一样简单,然后在控制器中从中读取,或者您可以使用 DB 或 linux fifo 管道或共享内存或任何您想要的。我会把那部分留给你,并假设你有相应的服务:

public function handle(\App\Events\SendSSE $event)
{
    // let's presume you have a helper method that will pass 
    // the message to the SSE Controller
    FifoBufferService::write($event->getMessage());
}

5) 最后,在您的 SSE 控制器中,您应该读取 fifo 缓冲区,并在收到新消息时将其传递给客户端:

while(1) {
    // if this read doesn't block, than you'll probably need to sleep()
    if ($new_msg = FifoBufferService::read()) {     
        $this->sendSSE($new_msg); 
    }
}

从未使用过 SSE,但根据他们的文档,我想到了两个解决方案:

1.Define 多个 EventSource 对象并在您的 js 中以不同方式处理它们:

var loginSource = new EventSource("{!! url("/loginsse") !!}");
var messageSource = new EventSource("{!! url("/messagesse") !!}");

2。在您的 sse.php 文件中,检查来自其他控制器的更新:

//sse.php called function
while(1) {
  $login = AuthController::postLogin($request);
  if ($login) return $login;

  $msg = FooController::sendMessage();
  if ($msg) return $msg;
  // ...
}

您需要创建 sendMessage()postLogin(Request $request) 静态方法。

还要考虑采用一些库来将 SSE 与 laravel 一起使用:快速 google 搜索为我提供了几种可能性。