编程

Laravel 使用 SSE 实现实时通知推送

28 2023-05-21 18:16:00

服务器发送事件(Server-Sent Events)

如果您曾经需要在web应用中实现实时功能,那么您可能对WebSockets的复杂性或长轮询的资源密集特性比较熟悉。

最近,我遇到这么一种场景,以上两个选项都不适合,就在那时,我发现了服务器发送事件(SSE),它不仅非常容易设置,而且还使我能够在使用WebSockets原本所需时间的一小部分内实现实时通信,在本文中,我们将使用此技术创建实时通知。

SSE 工作原理

SSE允许服务器向网页发送实时更新,而不需要客户端不断轮询新信息。

流程很简单,客户端与服务器建立连接,服务器在更新发生时通过该连接向客户端发送更新,这些更新作为“事件”发送,由一条消息和一个可选的事件名称组成。

然后,客户端可以通过显示通知或更新页面来对这些事件做出相应的反应。

只有当您的用例需要从服务器到客户端的单向通信时,SSE才是WebSockets的一个很好的替代方案。

让我们在 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的直接性(有局限性),还是WebSockets的多功能性(可用于所有用例,但实现起来很复杂)。