发送实时消息
接下来我们来实现当某个用户的账号在其他地方登录时,发送一个实时消息给当前的登录用户,告诉他的账号在其他设备登录了。
后端组件: laravel-websockets
,pusher
我们开始吧!
先来完成后端的功能,打开 .env
文件
PUSHER_APP_ID=123123 | |
PUSHER_APP_KEY=321321 | |
PUSHER_APP_SECRET=secret | |
PUSHER_APP_CLUSTER=mt1 |
这些是 pusher
的配置,随意填写,只需要保证和前端的 laravel-echo
一致即可。如果一台服务器上有多个站点,需要保证 id 和 key 的唯一性。
安装组件
laravel-websocets
依赖 guzzlehttp/psr7
组件的 1.5 版本,但是它的最新版本已经到 2.1
,而 guzzlehttp
也依赖它,并且要求最低是 1.8
两者相冲突了,所以不能直接使用 composer require
命令安装。
同样,pusher
也需要使用 3.0
版本。
打开 composer.json
"require": { | |
... | |
"guzzlehttp/psr7": "^1.5", | |
"beyondcode/laravel-websockets": "^1.12.0", | |
"pusher/pusher-php-server": "~3.0" | |
}, |
我们直接把这两个组件粘贴进去,然后执行命令:
composer update
发布 laravel-websockets
php artisan vendor:publish
在列表里选择 BeyondCode\LaravelWebSockets\WebSocketsServiceProvider
对应的序号。
Laravel
框架的消息推送功能默认使用的是 pusher
第三方 API 服务,我们使用 laravel-websocket
来拦截 pusher
发出的请求,转发到我们自己的服务器。
配置 websocket
关于 websockets
的配置,可以在 config/websockets.php
里找到
官方文档:点击这里
你只需要知道它在哪里即可,我们没有需要定制的配置。
然后打开 config/broadcasting.php
,修改 pusher
发送的请求地址为我们本地 ip 地址。
'connections' => [ | |
'pusher' => [ | |
... | |
'options' => [ | |
'cluster' => env('PUSHER_APP_CLUSTER'), | |
'encrypted' => true, | |
'host' => '127.0.0.1', | |
'port' => 6001, | |
'scheme' => 'http' | |
], | |
], |
好了,组件安装完成,执行命令启动 websocket
服务
php artisan websockets:serve
打开 your-project/laravel-websockets
可以看到控制台,点击 Connect
可以看到所有的发送消息明细。
推送消息
我们来创建一个事件,在每次用户登录成功后触发,执行命令:
php artisan make:event UserAuthenticatedEvent
还记得上一节提到的 authenticated
方法吗?我们在这个方法里面来触发事件:
public function authenticated(Request $request, $user) | |
{ | |
DB::table('sessions')->where('user_id', $user->id) | |
->update([ | |
'id' => DB::raw("concat('OUTMAN_', user_id, '_', id)"), | |
'user_id' => null | |
]); | |
// 触发广播事件,发送一个消息给之前的登录用户 | |
broadcast(new UserAuthenticatedEvent($user))->toOthers(); | |
} |
既然是广播事件,那就需要实现广播的接口,打开 UserAuthenticatedEvent.php
namespace App\Events; | |
use App\Models\User; | |
use Illuminate\Broadcasting\Channel; | |
use Illuminate\Broadcasting\InteractsWithSockets; | |
use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | |
use Illuminate\Foundation\Events\Dispatchable; | |
use Illuminate\Queue\SerializesModels; | |
class UserAuthenticatedEvent implements ShouldBroadcast | |
{ | |
use Dispatchable, InteractsWithSockets, SerializesModels; | |
public $user; | |
public function __construct(User $user) | |
{ | |
$this->user = $user; | |
} | |
public function broadcastOn() | |
{ | |
// 发送频道拼接 user_id,避免干扰 | |
return new Channel('outman-user-'. $this->user->id); | |
} | |
} |
再回到首页开 A,B 窗口登录,然后查看 storage/logs/laravel.log
[on channels [outman-user-1] with payload: | ] local.INFO: Broadcasting [App\Events\UserAuthenticatedEvent]|
{ | |
"user": { | |
"id": 1, | |
"name": "ricky", | |
"email": "ricky@me.com", | |
"email_verified_at": null, | |
"created_at": "2021-12-12T14:03:00.000000Z", | |
"updated_at": "2021-12-12T14:03:00.000000Z" | |
}, | |
"socket": null | |
} |
消息已经发出了,因为我们现在的 BROADCAST_DRIVER
还是 log,所以打印到了日志中。
下一节我们来完成前端实时显示通知。