如何避免服务器发送事件在 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 搜索为我提供了几种可能性。
所以我想在我的 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 搜索为我提供了几种可能性。