私人频道不适用于 Laravel 回显服务器

Posted

技术标签:

【中文标题】私人频道不适用于 Laravel 回显服务器【英文标题】:Private channel not working with Laravel echo server 【发布时间】:2017-09-05 03:13:30 【问题描述】:

我在控制台上收到这个 JS 错误:

app.js:167 Uncaught ReferenceError: receiverId is not defined

这是我的完整代码:

私人聊天控制器:

event(new PrivateMessageEvent($chat, $receiverId));

PrivateMessageEvent:

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;
use App\User;
use App\PrivateChat;

class PrivateMessageEvent implements ShouldBroadcast

    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $privateChat, $receiverId;
    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(PrivateChat $privateChat, $receiverId)
    
        $this->privateChat = $privateChat;
        $this->receiverId = $receiverId;
    

    /**
     * Get the channels the event should broadcast on.
     *
     * @return Channel|array
     */
    public function broadcastOn()
    
        return new PrivateChannel('private-chat.' . $this->receiverId);
    

Bootstrap.js

import Echo from "laravel-echo"

window.Echo = new Echo(
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001'
);

window.Echo.private(`private-chat.$receiverId`)
    .listen('PrivateMessageEvent', (e) => 
        console.log(e);
);

channels.php

Broadcast::channel('private-chat.receiverId', function ($user, $receiverId) 
    return true; // this is just for debugging to allow anyone to listen on this channel
    //return $user->id === $receiverId;
);

laravel-echo-server.json


    "authHost": "http://localhost",
    "authEndpoint": "/broadcasting/auth",
    "clients": [],
    "database": "redis",
    "databaseConfig": 
        "redis": ,
        "sqlite": 
            "databasePath": "/database/laravel-echo-server.sqlite"
        
    ,
    "devMode": true,
    "host": null,
    "port": "6001",
    "protocol": "http",
    "socketio": ,
    "sslCertPath": "",
    "sslKeyPath": ""

在后台 queue:worklaravel-echo-server 已经在运行

触发该事件后,我在 laravel-echo-server 控制台上收到此消息:

Channel: private-private-chat.
Event: App\Events\PrivateMessageEvent
CHANNEL private-private-chat.

注意事项:

我已成功收听公共频道。私人频道的唯一问题。

使用最新的 Laravel 版本,即 5.4

我已经按照官方文档做了所有的事情:

https://laravel.com/docs/master/broadcasting

https://github.com/tlaverdure/laravel-echo-server

我也在 github repo 上提出了问题:

https://github.com/tlaverdure/laravel-echo-server/issues/158

我已经花了 10 多个小时,尽我所能,但没有运气。

谢谢

【问题讨论】:

在触发事件之前,请执行dd($receiverId);。它说$receiverId 是空的吗? @jono20201,我已经检查了变量。它具有正确的值 - 不为空。 【参考方案1】:

您可以将REDIS_PREFIX 设置为NULL 以删除前缀,否则如果它有值,则必须在回显服务器配置中设置keyPrefix

如果REDIS_PREFIX = NULL 则不要添加keyPrefix


重要通知

使用broadcastAs() 时,对listen('') 的调用必须以点开头

此时使用keyPrefix时的行为未知,如果使用前缀设置,请评论DOT要求的结果。

https://laravel.com/docs/6.x/broadcasting#broadcast-name

public function broadcastAs()

    return 'server.created';

.listen('.server.created', function (e) 
    ....
);

我会检查自己的 DOT + PREFIX 组合,但我觉得如果我再继续使用 Laravel Echo,我会心脏病发作。


如果你不使用broadcastAs(),那么命名将回退到事件类名,在这种情况下没有注入DOT前缀,参见下面的设置:

laravel-echo-server.json


    "host": "127.0.0.1",
    "port": "6001",
    "protocol": "http",

    "database": "redis",

    "databaseConfig": 
        "redis": 
            "host": "127.0.0.1",
            "port": 6379,
            "db": 0,
            "keyPrefix": "VALUE OF REDIS_PREFIX"
        

/app/Events/MyExample.php

<?php

namespace App\Events;

use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;

class MyExample implements ShouldBroadcastNow


  private $id;

  public $payload;

  public function __construct($id, $payload)
  
    $this->id = $id;
    $this->payload = $payload;
  

  public function broadcastOn()
  
    return new PrivateChannel('example.' . $this->id);
  



触发事件 (PHP)


use App\Events\MyExample

$payload = [
 'duck' => 'sauce',
 'Bass' => 'Epic'
];

event(new MyExample($id, $payload))

监听事件 (JavaScript)

Echo.private(`example.$id`).listen('MyExample', event => 

  console.log('payload', event.payload)

)

【讨论】:

【参考方案2】:

尝试改变这一行:

$this->$receiverId = $receiverId;

到这一行:

$this->receiverId = $receiverId;

在您的 PrivateMessageEvent __construct() 中

更新:

尝试使用这样的固定频道 ID:

window.Echo.private('private-chat.1')

我建议你也使用出席频道,也是私人的,但有更多的功能,即:

Echo.join('private-chat.1')
   .listen('PrivateMessageEvent', (e) => 
    console.log(e);
);

如果您使用像您使用的动态频道号,即:

window.Echo.private(`private-chat.$receiverId`)

你必须在javascript中给receiverId一个值,这个声明是一个通用的房间监听器但是receiverId应该被定义,$receiverId是一个字符串插值。

你可以在引入app.js之前在模板中定义receiverId,例如使用刀片语法:

<script>
   receiverId =  $receiverId ;
</script>

另一个想法:我想明确一点,在上面的所有代码中,receiverId 代表客户想要加入的聊天/房间的 ID,而不是接收用户的 ID。

【讨论】:

好地方,但这只是写作中的一个错字。问题是别的东西 用 SO 或您的代码编写?因为 laravel-echo-server 输出也错过了recieverId。例如应该是Channel: private-private-chat.1 就这样。现已更正。【参考方案3】:

尝试代替event(new PrivateMessageEvent($chat, $receiverId)); 这个

App\Events\PrivateMessageEvent::dispatch($chat, $receiverId);

【讨论】:

【参考方案4】:

您需要做一些事情。

1) 删除频道名称开头的所有“private-”。这些由各种库(例如socket.io/laravel-echo)在幕后处理。如果您查看任何调试输出,您会看到通道名称前面附加了“private-”,但您不需要添加这些。

2) 如果您使用的是 redis,请确保在 .env 文件中将 REDIS_PREFIX 设置为空字符串。默认情况下,它设置为“laravel_database”之类的东西,这会弄乱频道名称。

REDIS_PREFIX=

3) 确保你的 laravel-echo 服务器正在运行(和 redis/pusher)。此外,您需要确保队列工作程序正在运行。就我而言,当我运行 redis 时,我必须运行:

php artisan queue:work redis

【讨论】:

以上是关于私人频道不适用于 Laravel 回显服务器的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Echo 私人频道和 Laravel echo 服务器 |雷迪斯

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

Laravel Echo 私人频道不听

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

Laravel 与 artisan serve 合作,但不适用于 vhost

Laravel 8 迁移:DB:unprepared 不适用于共享托管服务器