Laravel 使用 SSE 实现实时通知推送
服务器发送事件(Server-Sent Events)
如果你曾经需要在 web 应用中实现实时功能,那么你可能对 WebSocket 的复杂性或长轮询的资源密集特性比较熟悉。
最近,我遇到这么一种场景,以上两个选项都不适合,就在那时,我发现了服务器发送事件(SSE),它不仅非常容易设置,而且还使我能够在使用 WebSocket 原本所需时间的一小部分内实现实时通信,在本文中,我们将使用此技术创建实时通知。
SSE 工作原理
SSE 允许服务器向网页发送实时更新,而不需要客户端不断轮询新信息。
流程很简单,客户端与服务器建立连接,服务器在更新发生时通过该连接向客户端发送更新,这些更新作为“事件”发送,由一条消息和一个可选的事件名称组成。
然后,客户端可以通过显示通知或更新页面来对这些事件做出相应的反应。
只有当用例需要从服务器到客户端的单向通信时,SSE 才是 WebSocket 的一个很好的替代方案。
让我们在 Laravel 项目中使用吧
下图是预览
安装
我会使用 Laravel-wave 包实现 SSE。
首先创建一个新的 Laravel 应用
composer create-project laravel/laravel laravel-sse
服务器端的设置,只需拉取这个软件包即可
composer require qruto/laravel-wave
对于客户端设置,我们需要安装 Laravel Echo
以及随包附带的适配器
npm install --save-dev laravel-echo laravel-wave
我在这个demo中同时安装了 sweetalert2
npm install --save-dev sweetalert2
广播通知
请确保对 Laravel 广播事件进行配置,文档
首先创建一个 Lavavel 事件
php artisan make:event RealTimeNotification
我们需要对这个事件做些修改
- 使之实现
ShouldBroadcast
接口 - 使之返回
PrivateChannel
而非Channel
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class RealTimeNotification implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(
public string $message,
) {}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new Channel('events'),
];
}
}
然后我们需要配置 Laravel Echo
使之监听新建的事件。
在 bootstrap.js
中,添加下面代码
import Swal from 'sweetalert2';
import Echo from 'laravel-echo';
import { WaveConnector } from 'laravel-wave';
window.Echo = new Echo({ broadcaster: WaveConnector });
window.Echo.channel('events')
.listen('RealTimeNotification', (e) => {
Swal.fire({
position: 'top',
icon: 'success',
title: e.message,
showConfirmButton: false,
});
});
然后运行 Vite
开发服务器
npm run dev
这样,接收实时通知所要做的就完成了!
测试通知
首先,在 web.php
中添加一个路由
Route::view('real-time-notifications', 'sse');
resources/views/see.blade.php
中添加如下代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Real Time Notifications</title>
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
</head>
<body>
@vite('resources/js/app.js')
</body>
</html>
现在,我们只需要触发 RealTimeNotification
事件就行
启动 tinker
php artisan tinker
发送事件
event(new \App\Events\RealTimeNotification("Hello World!"))
现在你就能看到通知弹窗了!
小结
SSE 易于安装和使用,不过因为单向性,可能并不适用于所有项目。
既然你已经了解了它们,那么就由你来决定是使用 SSE 的直接性(有局限性0,还是 WebSocket 的多功能性(可用于所有用例,但实现起来很复杂)。