旧篇 => Laravel/Lumen 中使用 Echo + Socket.IO-Client 实现网页即时通讯广播 https://blog.csdn.net/maxsky/article/details/130394420 已过时
与时俱进,Laravel 官方在 2024 年 7 月发布了 laravel/reverb 包的正式版,因为之前使用的 laravel-echo-server 所使用的 socket.io-client 是比较老旧的 2.0 版本(而且是依赖 NodeJS,内存占用高)
所以更新了此博文帮助大家入门 laravel/reverb 的使用
内容与之前博文大同小异,我亦同步更新了 Laravel Echo 客户端的 Demo 供大家参考
因 laravel/reverb
最低支持框架版本为 Laravel 10.47+ 以及 PHP 8.2,博文发布时 Laravel 10 版本为 10.48.25,此处使用该框架作为示例(截止博文发布,laravel/reverb
未支持 Lumen 框架)
安装
执行 composer require laravel/reverb
安装 Reverb 即可
如果遇到网络问题,可参考该博文解决:Composer 2 镜像处理方案
安装成功后在项目根目录运行 php artisan
,可以看到 reverb
相关命令表示安装成功
配置
因为在 Laravel 10 中不存在 php artisan install
命令,所以部分工作需要我们手动完成
首先执行
php artisan reverb:install
该命令行会在 Laravel 10 框架中卡住,我们只需要检查下方相关内容是否成功变更后中断执行即可
- 检查
config/app.php
文件底部providers
部分 是否取消注释// App\Providers\BroadcastServiceProvider::class,
行,如果没有请手动取消,使BroadcastServiceProvider
类启用; - 检查
config/broadcasting.php
文件connections
部分是否出现了reverb
连接内容; - 检查
config
目录中是否出现了reverb.php
配置文件; - 检查根目录
.env
文件是否新增了 类似 如下内容:
需特别注意在命令执行期间可能造成 .env 中出现连续两个空行的情况,请自行删掉一行REVERB_APP_ID=122822 REVERB_APP_KEY=1vskpuauarymbej0on7d REVERB_APP_SECRET=nyk2kyajfnb0h86yrnoh REVERB_HOST="localhost" REVERB_PORT=8080 REVERB_SCHEME=httpVITE_REVERB_APP_KEY="${REVERB_APP_KEY}" VITE_REVERB_HOST="${REVERB_HOST}" VITE_REVERB_PORT="${REVERB_PORT}" VITE_REVERB_SCHEME="${REVERB_SCHEME}"
如果上方 四 项没有问题,可以 中断 reverb:install
命令
因为 Reverb 同样依赖了广播服务,我们需要在 .env
中修改或新增:
BROADCAST_DRIVER=reverb
发送广播
广播由事件组成,也就是说 因为发生了什么事,需要通知给某个人或者直接公布(所有人)
或者这样形容:广播就是喇叭,事件是通过喇叭“吼叫”(通知/发送)出去的。这就是我们需要创建事件的原因
事件
执行下方命令创建事件类 TestEvent
:
php artisan make:event TestEvent
该命令会在 app/Events
目录下创建 TestEvent
类。目前这个类非常简单,他有一个 broadcastOn
方法,也就是 通知给谁
注意这里默认的通知是一个 PrivateChannel
,也就是 私有频道。为了更简单的完成我们的示例,我们将其更改为 Channel
,并将中间的字符串更改为 channel-pub
(意为公共频道 public)
接着我们再为该类新增 public
修饰符的 $message
和 $broadcastTime
成员变量并修改构造函数,现在代码看起来是这样:
public string $message;
public string $broadcastTime;/*** Create a new event instance.*/
public function __construct(string $message) {$this->message = $message;$this->broadcastTime = Carbon::now()->toDateTimeString();
}
广播
上方我们虽然创建了需要广播的事件,但是这个事件并不会被(通过)广播发出去,因为事件类需要 实现 Illuminate\Contracts\Broadcasting\ShouldBroadcast
或 Illuminate\Contracts\Broadcasting\ShouldBroadcastNow
接口
ShouldBroadcastNow
为 立即广播,而 ShouldBroadcast
为 异步广播。根据需求你也应该知道使用哪一个接口,这里我们首先使用 ShouldBroadcastNow
进行接下来的操作
当前整个类的代码如下:
<?phpnamespace App\Events;use Carbon\Carbon;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;class TestEvent implements ShouldBroadcastNow {use Dispatchable, InteractsWithSockets, SerializesModels;public string $message;public string $broadcastTime;/*** Create a new event instance.*/public function __construct(string $message) {$this->message = $message;$this->broadcastTime = Carbon::now()->toDateTimeString();}/*** Get the channels the event should broadcast on.** @return array<int, Channel>*/public function broadcastOn(): array {return [new Channel('channel-pub'),];}
}
测试发送广播
和旧篇一样,编写一个测试路由即可。为了方便,我们在 routes/web.php
上方新增一个 Get 路由:
Route::get('/test_broadcast', function () {event((new App\Events\TestEvent('测试消息,Hello')));return 'Event broadcasted!';
});
然后继续下面的操作
接收广播
运行 Reverb 服务,在项目根目录执行:php artisan reverb:start --debug
,加上 debug
参数便于我们查询运行情况
如果没有问题,你会得到如下提示:
INFO Starting server on 0.0.0.0:8080 (localhost).
注意这个 0.0.0.0
和 8080
是基于 config/reverb.php
配置文件中的 host
和 port
决定
你可以在 .env
中配置 REVERB_SERVER_HOST
和 REVERB_SERVER_PORT
进行更改。该配置主要决定 Reverb 服务的地址和端口
下方提供两种方式进行测试,大家可以选择自己方便的一种即可
WebSocket 测试软件
例如 Postman、Apifox 等,这里以 Apifox 为例
在 Apifox 中新建 WebSocket 接口,接口地址填入 ws://127.0.0.1:8080/app/REVERB_APP_KEY
。注意把 REVERB_APP_KEY
替换为你 .env
文件中对应值,8080
端口对应 REVERB_SERVER_HOST
这里 127.0.0.1
似乎不能用 localhost
代替
填入地址后点击 连接,如果没有问题将得到下方结果:
{"event": "pusher:connection_established","data": "{\"socket_id\":\"676776035.185533755\",\"activity_timeout\":30}"
}
接着在消息中填入下方内容并点击 发送:
{"event": "pusher:subscribe","data": {"auth": "","channel": "channel-pub"}
}
得到订阅成功通知:
{"event": "pusher_internal:subscription_succeeded","data": "{}","channel": "channel-pub"
}
此时可以打开浏览器请求你项目的路由 /test_broadcast
,浏览器会显示 Event broadcasted!
表明广播已发送。
注意如果连接断开,重新连接并重新发送消息订阅即可
如果没有问题,你会收到类似下方广播内容表明接收成功:
{"event": "App\\Events\\TestEvent","data":"{\"message\":\"\中\文\测\试\",\"broadcastTime\":\"2025-01-08 03:05:20\"}","channel": "channel-pub"
}
Laravel-Echo-Client-Demo
这是一个前端 Demo 便于调试,地址:https://github.com/maxsky/Laravel-Echo-Client-Demo
通过 git
命令 clone
到本地后按 README.md 操作即可
在浏览器中运行该项目,然后请求 /test_broadcast
路由将会得到类似下方结果:
你也可以多次请求,网页内容不会清空:
以上就是即时广播的收发
异步广播
前文有提到,ShouldBroadcastNow
是 立即广播,而 ShouldBroadcast
是 异步广播。异步广播依赖 Redis 队列,所以在 .env
中需要配置好 Redis 连接以及修改 QUEUE_CONNECTION
配置为 redis
队列名
队列名在事件类中指定,我们在 TestEvent
类中添加下方内容:
public string $queue = 'broadcast';
在未指定的情况下,事件会存入 default
默认队列
此时新开命令窗口,在项目根目录下执行:
php artisan queue:work --queue=broadcast
随后浏览器中刷新请求 /test_broadcast
测试路由。有没有发现一个有趣的事,接收到的消息变成了:
{"queue": "broadcast","message": "测试消息,Hello","broadcastTime": "2025-01-08 03:21:28"
}
没错,默认情况下 消息会将所有 public 成员变量广播出去,让我们接着修改
指定广播内容
在 TestEvent
类中新增 broadcastWith
方法指定广播内容,经过一系列的修改,现在事件类看起来是这样:
<?phpnamespace App\Events;use Carbon\Carbon;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;class TestEvent implements ShouldBroadcast {use Dispatchable, InteractsWithSockets, SerializesModels;public string $queue = 'broadcast';public string $message;public string $broadcastTime;/*** Create a new event instance.*/public function __construct(string $message) {$this->message = $message;$this->broadcastTime = Carbon::now()->toDateTimeString();}/*** Get the channels the event should broadcast on.** @return array<int, Channel>*/public function broadcastOn(): array {return [new Channel('channel-pub'),];}/*** @return array*/public function broadcastWith(): array {return ['name' => 'MyTestEvent','message' => $this->message,'broadcastTime' => $this->broadcastTime];}
}
可以注意到我们在 broadcastWith
中手动指定了返回内容,我们 重新启动队列(修改事件后队列需要重启才会生效)并再次请求 /test_broadcast
路由:
我们成功过滤了 queue
成员变量,这保障了我们的隐私信息不会暴露出去
最后
Laravel Reverb 简化了操作和授权,具体的授权可参阅官方文档
熟悉之前 Socket.IO-Client
方式的小伙伴能更快上手,美中不足的是现在官方还未支持 Lumen 框架
此外在 Laravel-Echo-Client-Demo
的 js/app.js
代码内有相关说明,需要修改对应的 REVERB_APP_KEY
之类才可成功连接到 Reverb 服务