使用Socket.io将Laravel广播到私有频道

4
我正在尝试使用Laravel作为后端API客户端和SPA前端创建实时通知系统,我正在使用React作为前端,但是对于下面的示例,我将使用我创建的简单Vue.Js和blade以获取工作示例。
总之,我有一个路由触发事件,这类似于以下示例:
Route::get('fire', function () {
    // this fires the event
    $user = App\Models\User::find(1);
    event(new App\Events\CampaignUploadedWithSuccess($user, 'testing a notification'));
    return "event fired";
});

它触发的事件将看起来像这样:
<?php

namespace App\Events;

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

class CampaignUploadedWithSuccess implements ShouldBroadcast
{
    protected $user;

    public $notification;

    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @param $user
     * @param $notification
     */
    public function __construct($user, $notification)
    {
        $this->user = $user;
        $this->notification = $notification;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return Channel|array
     */
    public function broadcastOn()
    {
        return ['notifications-channel.' . $this->user->id];
    }
}

我正在一个名为notification-channel.{userId}的频道上广播。

然后,我有一个使用node运行的socket.js文件。

它看起来像这样:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');

var redis = new Redis();
redis.subscribe('notifications-channel.1', function(err, count) {
});
redis.on('message', function(channel, message) {
    console.log('Notification Recieved: ' + message);
    message = JSON.parse(message);
    io.emit(channel + ':' + message.event, message.data);
});
http.listen(3000, function(){
    console.log('Listening on Port 3000');
});

使用node socket.js运行服务器,触发事件会像下面这样实现我想要的效果:

Notification Recieved on localhost:3000

太棒了!我正在向一个频道广播。

然而,现在我有一个名为test.blade的blade文件,它将引入Vue和Socket.io

它看起来像这样:

<!DOCTYPE html>
<html>
<head>
    <title>Laravel</title>
</head>
<body>
<h1>Notifications</h1>

<ul>
    <li v-repeat="notification: notifications">@{{ notifications }}</li>
</ul>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.16/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.7/socket.io.min.js"></script>

<script>
    var socket = io('http://localhost:3000');
    new Vue({
        el: 'body',
        data: {
            notifications: []
        },
        ready: function() {
            socket.on('notifications-channel.1', function(data) {
                alert(data.notification);
            });
        }
    });
</script>
</body>
</html>

这里的目标是在通知通道1广播数据时,触发消息警报。但是它并没有起作用。

所以我的问题是,如何使用socket.io、Laravel和Redis将广播发送到频道并从频道消费广播。

我对私有频道也有些不了解,不知道如何创建一个仅供一个用户使用的频道。文档很好,但没有提供实现此目的并使多个平台消耗通知的真实世界示例。

2个回答

2

在搜索后,我也遇到了同样的问题,发现问题是由于套接字版本引起的。请确保您在服务器端和客户端使用了相同的socket.io版本,您可以通过首先检查package.json文件中的套接字版本来验证此内容,就像在我的情况下一样,您可以看到以下内容:

"devDependencies": {
    "socket.io": "^2.0.3",
    "socket.io-client": "^2.0.3",
 }

然后在你的test.blade文件中,像下面这样验证socket版本

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>

你可以看到这两个版本是相同的。
你的Blade文件中有一个问题,你通过键通道:事件名称发出socket事件,但在你的Blade文件中,你只能监听通道名称而不是连接事件名称。请用以下代码替换它。
<script>
    var socket = io('http://localhost:3000');
    new Vue({
        el: 'body',
        data: {
            notifications: []
        },
        ready: function() {
            socket.on('notifications-channel.1:App\\Events\\CampaignUploadedWithSuccess', function(data) {
                alert(data.notification);
            });
        }
    });
</script>

这很有道理,所以我修改了刀片文件,当我在浏览器中运行它时,我看到我的H1标签,显示通知,控制台显示错误连接被拒绝,所以我运行node socket.js,那个错误就消失了,在我的脑海中,这意味着它连接到localhost:3000,我触发事件,它出现在服务器控制台上,但不会在客户端上进行控制台日志记录...我使版本匹配 :) - user4796879
我认为我可能在我的socket.js文件中缺少与套接字的连接。 - user4796879
让我们在聊天中继续这个讨论 - Shahid Ahmad
-1,请使用代码块而不是图片,这样任何重要的代码都可以复制到用户的编辑器中。请注意,您可以使用“<!-- language html -->”来为某些代码块提供所需的语言格式。 - Ferrybig
@Ferrybig,我已经更新了我的答案,你现在可以查看它。 - Shahid Ahmad
显示剩余5条评论

0
我认为您忽略了io的设置,请查看。

https://socket.io/docs/server-api/

您的Node.js服务器和/或客户端需要类似于这样的内容。

io.on('connect', onConnect);

function onConnect(socket){
   socket.emit(channel + ':' + message.event, message.data);
}

希望这有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接