Laravel 13 WebSocket 与实时通信详解

摘要

Laravel 的广播系统允许实时推送事件到前端。本文将深入讲解 Laravel 13 的 WebSocket 与实时通信,包括:

  • 广播配置
  • 事件广播
  • 私有频道
  • Laravel Echo
  • 实战案例与最佳实践

本文适合希望构建实时应用的 Laravel 开发者。

1. 配置

1.1 广播配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// config/broadcasting.php
'default' => env('BROADCAST_DRIVER', 'pusher'),

'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true,
],
],

'ably' => [
'driver' => 'ably',
'key' => env('ABLY_KEY'),
],

'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
],

1.2 启用广播

1
2
3
4
// config/app.php
'providers' => [
App\Providers\BroadcastServiceProvider::class,
],

2. 定义广播事件

2.1 创建广播事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderShipped implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public function __construct(
public Order $order
) {}

public function broadcastOn(): array
{
return [
new PrivateChannel('orders.' . $this->order->user_id),
];
}

public function broadcastWith(): array
{
return [
'id' => $this->order->id,
'status' => $this->order->status,
];
}
}

2.2 广播队列

1
2
3
4
5
6
7
class OrderShipped implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;

public $connection = 'redis';
public $queue = 'broadcasts';
}

3. 频道

3.1 公共频道

1
2
3
4
5
6
public function broadcastOn(): array
{
return [
new Channel('orders'),
];
}

3.2 私有频道

1
2
3
4
5
6
public function broadcastOn(): array
{
return [
new PrivateChannel('orders.' . $this->order->user_id),
];
}

3.3 存在频道

1
2
3
4
5
6
public function broadcastOn(): array
{
return [
new PresenceChannel('chat.' . $this->chat->id),
];
}

4. 频道授权

4.1 定义路由

1
2
3
4
5
6
// routes/channels.php
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('orders.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});

4.2 模型绑定

1
2
3
Broadcast::channel('orders.{order}', function ($user, Order $order) {
return $user->id === $order->user_id;
});

5. 前端集成

5.1 安装 Laravel Echo

1
npm install --save-dev laravel-echo pusher-js

5.2 配置 Echo

1
2
3
4
5
6
7
8
9
10
11
12
// resources/js/bootstrap.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true
});

5.3 监听公共频道

1
2
3
4
Echo.channel('orders')
.listen('OrderShipped', (e) => {
console.log(e.order);
});

5.4 监听私有频道

1
2
3
4
Echo.private(`orders.${userId}`)
.listen('OrderShipped', (e) => {
console.log(e.order);
});

5.5 监听存在频道

1
2
3
4
5
6
7
8
9
10
11
12
13
Echo.join(`chat.${chatId}`)
.here((users) => {
console.log('Users in chat:', users);
})
.joining((user) => {
console.log('User joined:', user);
})
.leaving((user) => {
console.log('User left:', user);
})
.listen('MessageSent', (e) => {
console.log(e.message);
});

6. 实战案例

6.1 实时聊天

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace App\Events;

use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use App\Models\Message;

class MessageSent implements ShouldBroadcast
{
public function __construct(
public Message $message
) {}

public function broadcastOn(): array
{
return [
new PresenceChannel('chat.' . $this->message->chat_id),
];
}
}
1
2
3
4
Echo.join(`chat.${chatId}`)
.listen('MessageSent', (e) => {
this.messages.push(e.message);
});

6.2 通知广播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

namespace App\Notifications;

use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\BroadcastMessage;

class OrderUpdated extends Notification
{
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage([
'order_id' => $this->order->id,
'status' => $this->order->status,
]);
}

public function broadcastOn()
{
return ['user.' . $this->order->user_id];
}
}

7. 最佳实践

7.1 使用队列

1
2
3
4
5
// 推荐:使用队列广播
class OrderShipped implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
}

7.2 限制广播数据

1
2
3
4
5
6
7
public function broadcastWith(): array
{
return [
'id' => $this->order->id,
'status' => $this->order->status,
];
}

8. 总结

Laravel 的广播系统提供了强大的实时通信能力:

  1. 事件广播:自动推送事件
  2. 频道授权:安全的频道访问
  3. 多种驱动:Pusher、Ably、Redis
  4. 前端集成:Laravel Echo 支持

参考资料