Laravel WebSockets:订阅私人频道不起作用

时间:2019-11-12 10:25:17

标签: laravel vue.js websocket pusher laravel-broadcast

软件:

在websockets.php(complete file)中,我设置了local_certlocal_pk以及证书。如果我将此选项留空,我什至无法连接。我还将verify_peer设置为false,因为如果不这样做,我也无法连接。

broadcasting.php:

'pusher' => [
        'driver' => 'pusher',
        'key' => env('PUSHER_APP_KEY'),
        'secret' => env('PUSHER_APP_SECRET'),
        'app_id' => env('PUSHER_APP_ID'),
        'options' => [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            'host' => '127.0.0.1',
            'port' => 6001,
            'scheme' => 'https',
            'curl_options' => [
                CURLOPT_SSL_VERIFYHOST => 0,
                CURLOPT_SSL_VERIFYPEER => 0,
            ]
        ],
    ],

如果我摆脱了curl选项,我将得到一个空的Broadcast异常like described here

bootstrap.js:

window.Pusher = require('pusher-js');
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: '7d23096ae0ab2d02d220',
    wsHost: window.location.hostname,
    wsPort: 6001,
    wssPort: 6001,
    encrypted: true,
    disableStats: true,
    auth: {
        headers: {
            'X-CSRF-TOKEN': window.App.csrfToken,
        },
    },
})

这是我在运行php artisan websockets:serve后从日志中得到的所有信息:

New connection opened for app key 7d23096ae0ab2d02d220.
Connection id 49092664.114416323 sending message {"event":"pusher:connection_established","data":"{\"socket_id\":\"49092664.114416323\",\"activity_timeout\":30}"}

我应该得到的是有关侦听/加入频道以及发送消息等消息,但是目前所有这些都无法正常工作。我有类似的东西:

Echo.private('notifications.' + this.user.id)
                .listen('UserNotificationSent', (e) => {
                    console.log(e)
                })

事件:例如UserNotificationSent.php

当然,在内部,我还进行了其他所有设置:带有auth的通道等。所有内容均在较低Laravel版本(5.4)的计算机上本地运行。但是我最近更新到5.8并部署到服务器,现在我为此感到困惑。

我也是opened an issue on github

重要更新 这实际上不是由于部署造成的,我在本地设置中也遇到了同样的问题。有趣的是,通过Echo.channel()收听频道有效,但是.private()无效。在Github(上面的链接)上,我遇到了一个完全相同的问题的人。我们尚未找到解决方案。

3 个答案:

答案 0 :(得分:0)

发生这种情况是因为端口6001在实时服务器上的nginx中已保留(底部有说明)。我需要在nginx上使用反向代理才能使其正常工作-并将端口6002用于实时服务器中的websocket。

nginx (应要求,我添加了完整的nginx代码)

server {

  #The nginx domain configurations
  root /var/www/laravel/public;
  index index.html index.htm index.php index.nginx-debian.html;
  server_name example.com www.example.com;

  #WHAT YOU NEED IS FROM HERE...
  location / {
      try_files $uri $uri/ /index.php?$query_string;

      # "But why port 6000, 6002 and 433? Scroll at the bottom"

      proxy_pass                          http://127.0.0.1:6001;
      proxy_set_header Host               $host;
      proxy_set_header X-Real-IP          $remote_addr;

      proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto  https;
      proxy_set_header X-VerifiedViaNginx yes;
      proxy_read_timeout                  60;
      proxy_connect_timeout               60;
      proxy_redirect                      off;

      # Specific for websockets: force the use of HTTP/1.1 and set the Upgrade header
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection 'upgrade';
      proxy_set_header Host $host;
      proxy_cache_bypass $http_upgrade;
 }
 #..UNTIL HERE - The rest are classic nginx config and certbot

 #The default Laravel nginx config
 location ~ \.php$ {
      try_files $uri =404;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass unix:/run/php/php7.2-fpm.sock;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      include fastcgi_params;
 }

 #SSL by certbot
 listen [::]:443 ssl ipv6only=on; # managed by Certbot
 listen 443 ssl; # managed by Certbot

 ssl                         on;
 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
 ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
 include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
 ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

 ssl_session_cache           shared:SSL:30m;
 ssl_protocols               TLSv1.1 TLSv1.2;

 # Diffie Hellmann performance improvements
 ssl_ecdh_curve              secp384r1;
}

所有通过TLS连接到您的域的内容都将以纯文本格式代理到端口6001上的本地服务。这会将所有TLS(和证书管理)卸载到Nginx,从而使您的websocket服务器配置尽可能简洁明了。

这也使通过“加密”的自动化变得更加容易,因为已经有一些实现可以管理Nginx中的证书配置并在需要时重新加载它们。-Source - Mattias Geniar

回声设置:

let isProduction = process.env.MIX_WS_CONNECT_PRODUCTION === 'true';

Vue.prototype.Echo = new LaravelEcho({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    wssHost: window.location.hostname,
    wssPort: isProduction ? 6002 : 6001,
    wsHost: window.location.hostname,
    wsPort: isProduction ? 6002 : 6001,
    disableStats: false,
    encrypted: isProduction,
    enabledTransports: ['ws', 'wss'],
    disabledTransports: ['sockjs', 'xhr_polling', 'xhr_streaming']
});

websockets.php

'apps' => [
    [
        'id' => env('MIX_PUSHER_APP_ID'),
        'name' => env('APP_NAME'),
        'key' => env('MIX_PUSHER_APP_KEY'),
        'secret' => env('MIX_PUSHER_APP_SECRET'),
        'enable_client_messages' => false,
        'enable_statistics' => true,
    ],
],

// I kept them null but I use LetsEncrypt for SSL certs too.
'ssl' => [
   'local_cert' => null,
   'local_pk' => null,
   'passphrase' => null,
]

broadcasting.php

'pusher' => [
     'driver' => 'pusher',
     'key' => env('MIX_PUSHER_APP_KEY'),
     'secret' => env('MIX_PUSHER_APP_SECRET'),
     'app_id' => env('MIX_PUSHER_APP_ID'),
     'options' => [
         'cluster' => env('MIX_PUSHER_APP_CLUSTER'),
         'encrypted' => env('MIX_WS_CONNECT_PRODUCTION'),
         'host' => '127.0.0.1',
         'port' => env('MIX_WS_CONNECT_PRODUCTION') ? 6002 : 6001,
         'scheme' => 'http'
     ],
 ],

这是我的整个工作周期,这使其得以发挥作用。希望对您有所帮助。


  

引用Alex Bouma's explanation

     

“但是为什么端口6000、6002和433真是一团糟!”

     

我听到了!让我解释一下,希望以后一切都会有意义。

     

这就是问题,一次只能在一个应用程序上打开服务器上的端口(从技术上讲,这不是正确的,但让我们在此保持简单)。因此,如果我们让NGINX在端口6001上侦听,我们将无法在端口6001上也启动我们的websockets服务器,因为它将与NGINX冲突,反之亦然,因此我们让NGINX在端口6002上侦听并使其代理(NGINX是反向代理)毕竟)通过纯http到端口6001(websockets服务器)的所有流量。剥离SSL,因此websockets服务器无需知道如何处理SSL。

     

因此NGINX将处理所有SSL魔术,并将纯HTTP流量转发到Websockets服务器正在侦听请求的服务器上的端口6001。

     

之所以没有在websockets.php配置中配置任何SSL,而是在broadcast.php中将方案定义为http并使用端口6001的原因,是为了绕过NGINX并直接与本地的websockets服务器通信,而无需SSL,速度更快(更易于配置和维护)。

答案 1 :(得分:0)

我发现了问题。

我在web.php中有这个东西:

Route::post('/broadcasting/auth', function (Illuminate\Http\Request $req) {
if ($req->channel_name == 'users') {
    return Broadcast::auth($req);
}
});

我不完全记得为什么以及何时添加它,但这可能来自here。由于某种原因,这不会产生任何错误。无论如何,我摆脱了这一点,现在它就像一种魅力一样工作。

答案 2 :(得分:-3)

在事件中使用broadcastAs()方法

public function broadcastAs()
{
    return 'UserNotificationSent';
}

这样听。

.listen('.UserNotificationSent', function (e) {
    ....
});

在UserNotificationSent事件之前放置点(。)来监听

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