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

时间:2017-09-22 09:32:21

标签: laravel sockets websocket socket.io laravel-5.4

我正在尝试创建一个实时通知系统,使用Laravel作为后端API客户端和SPA为我的前端,我使用React作为前端,但对于下面的示例我将使用一个简单的Vue.Js我创建的刀片是为了得到一个有效的例子。

所以,总而言之,我有一条触发事件的路线,如下例所示:

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}

的频道上播放

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

看起来像这样

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的刀片文件,它将引入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>

此处的目标是在notification-channel.1向其广播数据时让消息发出警报。但这不起作用。

所以我的问题是,如何使用socket.io,Laravel和Redis广播到频道并使用该频道播放该广播。

私人频道我也有点黑暗,以及我如何只为一个用户创建一个频道。该文档很好,但它没有提供如何实现此目的的实际示例,并且有多个平台消耗的通知。

2 个答案:

答案 0 :(得分:2)

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

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

然后验证test.blade文件中的套接字版本,如下所示

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

你可以看到这两个版本是相同的。

并且您的刀片文件中存在一个问题,即您通过密钥通道发出套接字事件:event.name但是在刀片文件上,您只能监听通道名称而不连接事件名称。请将其替换为以下代码

<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>

答案 1 :(得分:1)

我认为你错过了io的设置

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

您的nodejs服务器和/或客户端上需要这样的东西。

io.on('connect', onConnect);

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

希望这有帮助