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

Posted

技术标签:

【中文标题】Laravel 使用 Socket.io 广播到私人频道【英文标题】:Laravel Broadcast to a private channel using Socket.io 【发布时间】:2018-03-03 20:06:03 【问题描述】:

我正在尝试使用 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 文件。

看起来像这样

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 运行服务器并触发事件执行我想要的如下操作:

快乐的日子!我正在向一个频道广播..

但是,我现在有一个名为 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 向频道广播并使用该频道的广播。

我对私人频道以及如何只为一个用户创建频道也有些摸不着头脑。文档很好,但它没有提供如何实现这一点的真实示例以及如何让多个平台使用通知。

【问题讨论】:

【参考方案1】:

搜索后我也遇到了同样的问题,我发现问题是由于套接字版本造成的。请确保您在服务器端和客户端都使用了相同的 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>

你可以看到这两个版本是一样的。

在刀片文件中存在一个问题,您通过键 channel: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>

【讨论】:

这很有意义,所以我更改了刀片文件,当我在浏览器中运行它时,我看到我的 H1 标签,说通知,控制台显示错误连接被拒绝,所以我运行node socket.js 并且该错误消失了,在我看来,这意味着它连接到 localhost:3000,我触发了该事件,它显示在服务器控制台中但不会控制台登录客户端...我使版本匹配:) 我想我的 socket.js 文件中可能缺少与套接字的连接 您广播您的活动的频道名称为通知频道,然后您动态传递用户 ID,并在客户端将其硬编码为 1。您当前登录的用户是否有 ID 1请确认。 不,你的 socket.js 文件没问题,我和我匹配,没问题 啊那肯定是在blade文件的某个地方,我从这里调试...【参考方案2】:

我认为您缺少 io 查看的设置

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

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

io.on('connect', onConnect);

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

希望对你有帮助

【讨论】:

以上是关于Laravel 使用 Socket.io 广播到私人频道的主要内容,如果未能解决你的问题,请参考以下文章

laravel5.5事件广播系统实例laravel-echo + redis + socket.io

Laravel Homestead , Socket.io 连接被拒绝

Laravel 事件广播没有被拾取 laravel-echo-server

无法使用 Laravel echo server、redis 和 socket.io 验证 laravel 私人频道

Quasar Vue Socket.io Laravel-Echo 实现

广播 laravel 事件和多个频道