带有 socket-io 的 Laravel 事件 [接收通知]
Posted
技术标签:
【中文标题】带有 socket-io 的 Laravel 事件 [接收通知]【英文标题】:Laravel event with socket-io [receive notifications] 【发布时间】:2020-08-26 17:41:43 【问题描述】:第一次尝试使用laravel
和socket-io
我正在尝试向管理员发送非常简单的通知。 到目前为止,我的事件正在触发,但我在接收事件通知方面需要帮助。
逻辑
这是非常基础的,因为我想了解这个过程。
-
用户打开页面
Add Product
管理员收到user X
在App Product
页面中的通知。
到目前为止
到目前为止,我可以触发事件并获取用户数据(Add Product
页面中的用户)
需要帮助
我需要帮助来了解管理员接收通知的方式。
代码
组件脚本
created()
let user = JSON.parse(localStorage.getItem("user"))
this.listenForBroadcast(user);
,
methods:
listenForBroadcast(user)
Echo.join('userInAddProduct')
.here((Loggeduser) =>
console.log('My user data', Loggeduser);
);
以上代码的结果
My user data […]
0:
id: 1
name: "Test User"
photo: "User-1588137335.png"
__ob__: Observer value: …, dep: Dep, vmCount: 0
get id: ƒ reactiveGetter()
set id: ƒ reactiveSetter(newVal)
get name: ƒ reactiveGetter()
set name: ƒ reactiveSetter(newVal)
get photo: ƒ reactiveGetter()
set photo: ƒ reactiveSetter(newVal)
__proto__: Object
length: 1
__proto__: Array(0)
渠道路线
Broadcast::channel('userInAddProduct', function ($user)
return [
'id' => $user->id,
'photo' => $user->photo,
'name' => $user->name
];
);
MessagePushed(事件文件)
class MessagePushed implements ShouldBroadcast
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public function __construct(User $user)
$this->user = $user;
public function broadcastOn()
return new PresenceChannel('userInAddProduct');
问题
如何接收有关此事件触发的通知?我想通知我的管理员用户 user x
在页面 Add Product
中?
更新
自从我发布这个问题以来,我做了一些更改,这是我最新的代码 + 问题。
bootstrap.js
window.io = require('socket.io-client');
window.Echo = new Echo(
broadcaster: 'socket.io',
host: window.location.hostname + ':6001',
auth: // added authentication token (because all my events are private)
headers:
Authorization: localStorage.getItem('access_token'),
,
,
);
Add.vue (add product component where event has to be fired)
listenForBroadcast(user)
let ui = JSON.parse(localStorage.getItem("user"))
Echo.join('userInAddProduct')
.here((users) =>
console.log('My user data', users)
)
.joining((user) =>
this.$notify(
title: '',
message: user + 'joining',
offset: 100,
type: 'success'
);
)
.leaving((user) =>
this.$notify(
title: '',
message: user + 'is leaving new product',
offset: 100,
type: 'warning'
);
)
.whisper('typing', (e) =>
this.$notify(
title: '',
message: ui.username + 'is adding new product',
offset: 100,
type: 'success'
)
)
.listenForWhisper('typing', (e) =>
console.log(e)
this.$notify(
title: '',
message: ui.username + 'is entered add new product page.',
offset: 100,
type: 'success'
);
)
.notification((notification) =>
console.log('noitication listener: ', notification.type);
);
,
然后我制作了 4 个文件来处理事件:
事件 (passing data
)
事件监听器(process the database storage
和 showing notifications
在线管理员)
观察者(射击事件)
通知(store data to database
为管理员提供,以防事件触发时他们不在线,以便他们稍后可以看到通知)
Event file
class MessagePushed extends Event implements ShouldBroadcast
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $product;
public function __construct(User $user, Product $product)
$this->user = $user;
$this->product = $product;
public function broadcastOn()
return new PresenceChannel('userInAddProduct');
Listener file
class ThingToDoAfterEventWasFired implements ShouldQueue
public function handle(MessagePushed $event)
//Log testing purpose only
$user = $event->user->username;
$product = $event->product->name;
// Real data that should be broadcasts
$user2 = $event->user;
$product2 = $event->product;
// inform all admins and authorized staffs about new product
$admins = User::role(['admin', 'staff'])->get();
foreach($admins as $admin)
$admin->notify(new UserAddProduct($user2, $product2));
Log::info("Product $product was Created, by worker: $user");
Notification
class UserAddProduct extends Notification implements ShouldQueue
use Queueable;
protected $product;
protected $user;
public function __construct(User $user, Product $product)
$this->product = $product;
$this->user = $user;
public function via($notifiable)
return ['database', 'broadcast'];
public function toDatabase($notifiable)
return [
'user_id' => $this->user->id,
'user_username' => $this->user->username,
'product_id' => $this->product->id,
'product_name' => $this->product->name,
];
public function toArray($notifiable)
return [
'id' => $this->id,
'read_at' => null,
'data' => [
'user_id' => $this->user->id,
'user_username' => $this->user->username,
'product_id' => $this->product->id,
'product_name' => $this->product->name,
],
];
Observer
public function created(Product $product)
$user = Auth::user();
event(new MessagePushed($user, $product));
问题
-
如何在在整个应用程序中触发事件后立即返回实时通知?目前我的代码放在
add.vue component admins get notify IF they are in same page only :/
如何获得多个事件的通知?假设我有另一个 event, listener, observer
用于其他页面操作,我希望管理员在整个应用中同时收到 product event
和 other event
的通知。
谢谢
【问题讨论】:
你在客户端使用 socket.io:socket.io/docs 吗?如果是,您可以简单地使用 socket.on('event_fire_name', function() /* */ );在管理面板中接收通知 @AhmedRebai 是的,我在客户端使用套接字,您有任何示例代码可以分享作为答案吗? @maforis 看看官方文档socket.io/docs/client-api,它会指导你 ....没有人?! :// @Shizzen83 非常感谢你,迫不及待想看:) 【参考方案1】:我们区分公共和私人等渠道类型。
公共:照亮\广播\频道。它无需任何身份验证即可工作,因此匿名用户可以收听此广播。就像所有人都可以看到的足球比赛比分一样。
私人:照亮\广播\私人频道。它与身份验证一起使用,因此只有经过身份验证的用户才能收听此广播。就像管理员查看特定用户的操作或用户查看他们的订单状态一样。
另一方面,还有另一个私有频道,即 Illuminate\Broadcasting\PresenceChannel。还需要认证。例如,就像任何聊天室一样。例如:只有经过身份验证的用户才能相互通信。
所以这些类型将定义您的方法。你必须走不同的道路。我非常建议阅读 Laravel 文档 (https://laravel.com/docs/broadcasting),它会非常仔细地指导你。
在 routes/channels.php 中,您必须决定或验证经过身份验证的用户是否可以收听此特定频道。所以你必须返回布尔值(真或假)。因此,在这里,您不会向客户端返回任何值。
MessagePushed 广播事件中的每个公共属性都将被序列化并发送到客户端。您必须将每个信息数据提供给 MessagePushed 构造函数并设置为属性/属性。现在您可以像这样处理接收到的数据,例如:
window.Echo = new Echo(
broadcaster: 'socket.io',
host: window.location.hostname + ':6001',
auth:
headers:
'X-Auth-Token': "<token>"
);
window.Echo.private('userInAddProduct')
.listen('MessagePushed ', (e) =>
console.log(e.auction);
);
我建议使用令牌创建自定义身份验证。上面我将令牌发送到服务器以验证用户。 https://laravel.com/docs/authentication#adding-custom-guards
在你的情况下,我会将这两种机制分开。
-
检查用户是否进入应用产品页面
通知管理员
对于第二点,使用 Illuminate\Broadcasting\PrivateChannel 就足够了。所以在管理页面上需要 websocket。 1. 点可能很棘手,因为这取决于您的要求。通知管理员用户进入确切的应用产品页面就足够了?
如果是,那么当用户访问该页面时,您将在控制器中触发此广播事件。
如果还不够,那么您需要用户页面上的另一个 websocket 来“轮询”您的服务器并每隔 X 秒向管理员发送一次滴答广播。
触发广播事件:
broadcast(new App\Events\MessagePushed($user));
我的用法是:
客户端:socket.io-client 服务器端:laravel-echo-server redis 广播器 自定义身份验证机制希望,我能帮上忙!
【讨论】:
感谢您的回答,您介意查看我的更新吗?我认为这可能会帮助您理解我的问题,从而更好地帮助我:) 欣赏它。 我认为您在实现目标方面走错了路。我怎么说 PresenceChannel 就像聊天室,并不是监控用户的最佳选择。您想以哪种方式通知管理员用户,仅使用 websocket? 老实说,我对此有点困惑,我的总体计划是:如果管理员在线(在任何页面中)获取实时通知。如果他的离线通知存储在数据库中,并且他一上线就看到它。 你有什么建议? 在这种情况下,我将为管理员用户创建脚本,该脚本将加载到每个页面上,该脚本包含 socket.io 连接。 (window.Echo = 新的 Echo ...)。当用户是管理员时,您可以包含此脚本。这些特定的控制器会调用一些 CustomHandlerClass 来将查看操作存储到数据库中。所以也许你可以创建一个监控模型来存储和获取用户视图。您也可以在此 CustomHandlerClass “broadcast(new App\Events\MessagePushed($user));”中触发广播。因此,您将每次都存储到数据库中,但您也发送广播。【参考方案2】:我最近写了一篇文章How to use Laravel WebSockets for NuxtJs notifications,我在其中详细描述了 Laravel WebSockets 的事件设置。我希望你觉得它有用。
【讨论】:
谢谢你,如果没有工作或有任何问题,我会阅读并回复你 好吧,你在 nuxt 配置文件上迷路了,我不使用 nuxt(甚至没有安装在我的应用程序中)但是你放置在那里的配置已经存在于我的bootstrap.js
文件中(你可以看到它在更新部分)你有什么建议?【参考方案3】:
已解决
这是我根据我的需要和我的问题完成的(如果你的情况与我的不同,它可能会有所不同)
在该活动发生的组件中(在我的情况下为Add.vue
)
Echo.join('userInAddProduct')
.here((users) =>
console.log('here: ', users);
)
.joining((user) =>
console.log('joining: ', user);
)
.leaving((user) =>
console.log('leaving: ', user);
)
.whisper('typing', data: notf) // this part sends my data
.notification((notification) =>
console.log('noitication listener1: ', notification.type);
);
由于我需要我的通知在所有页面中对管理员可见,我已将我的套接字发射(即Echo.listenForWhisper
)添加到我的导航栏组件中。
mounted()
this.notifs();
window.Echo.join('userInAddProduct')
// listen to broadcast from Add.vue
.listenForWhisper('typing', (product) =>
// add it into my navbar notifications list
this.notifications.unshift(product);
);
现在每次用户向服务器管理员添加新产品时都会收到通知。
注意要查看我的其他设置,请滚动回我的更新部分并查看Event, Listener & Observe
文件代码。 (您将这些文件和上面的所有这些代码制作成您喜欢的组件,然后您将获得实时通知)。
【讨论】:
以上是关于带有 socket-io 的 Laravel 事件 [接收通知]的主要内容,如果未能解决你的问题,请参考以下文章