【问题标题】:Beyondcode Laravel Websockets : failed: WebSocket is closed before the connection is establishedBeyondcode Laravel Websockets:失败:在建立连接之前关闭WebSocket
【发布时间】:2020-02-03 11:18:38
【问题描述】:

本地 websockets 运行良好,但在生产中我不断收到标题中的错误。

我正在使用 websocket 包的一些背景信息:beyondcode/laravel-websockets。我正在与主管一起运行 'php artisan websockets:serve --port=6004'。我还确保端口 6004 已打开。

在生产中,我尝试了使用和不使用 SSL 的设置都在标题中给出了错误。

SSL 设置:

我的回声设置:

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    wsHost: window.location.hostname,
    wsPort: 6004,
    wssPort: 6004,
    disableStats: true,
    enabledTransports: ['ws', 'wss'],
});

我的推送器设置:

'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'),
                'encrypted' => true,
                'host' => '127.0.0.1',
                'port' => 6004,
                'scheme' => 'https',
                'curl_options' => [
                    CURLOPT_SSL_VERIFYHOST => 0,
                    CURLOPT_SSL_VERIFYPEER => 0,
                ]
            ],
        ],

我的 websockets 设置:

'apps' => [
        [
            'id' => env('PUSHER_APP_ID'),
            'name' => env('APP_NAME'),
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'enable_client_messages' => true,
            'enable_statistics' => true,
        ],
    ],

    'ssl' => [
        /*
         * Path to local certificate file on filesystem. It must be a PEM encoded file which
         * contains your certificate and private key. It can optionally contain the
         * certificate chain of issuers. The private key also may be contained
         * in a separate file specified by local_pk.
         */
        'local_cert' => base_path().'/ssl/server.crt',

        /*
         * Path to local private key file on filesystem in case of separate files for
         * certificate (local_cert) and private key.
         */
        'local_pk' => base_path().'/ssl/server.pem',

        /*
         * Passphrase for your local_cert file.
         */
        'passphrase' => null,
        'verify_peer' => false,
    ],

没有 SSL 的设置:

我的回声设置:

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    wsHost: window.location.hostname,
    wsPort: 6004,
    disableStats: true,
    enabledTransports: ['ws', 'wss'],
});

我的推送器设置:

'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'),
                'encrypted' => false,
                'host' => '127.0.0.1',
                'port' => 6004,
                'scheme' => 'http',
            ],
        ],

我的 websockets 设置:

'apps' => [
        [
            'id' => env('PUSHER_APP_ID'),
            'name' => env('APP_NAME'),
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'enable_client_messages' => true,
            'enable_statistics' => true,
        ],
    ],

    'ssl' => [
        /*
         * Path to local certificate file on filesystem. It must be a PEM encoded file which
         * contains your certificate and private key. It can optionally contain the
         * certificate chain of issuers. The private key also may be contained
         * in a separate file specified by local_pk.
         */
        'local_cert' => null,

        /*
         * Path to local private key file on filesystem in case of separate files for
         * certificate (local_cert) and private key.
         */
        'local_pk' => null,

        /*
         * Passphrase for your local_cert file.
         */
        'passphrase' => null,

    ],

【问题讨论】:

    标签: laravel websocket echo pusher


    【解决方案1】:

    我也遇到了这个问题,并发布了一个更详细的问题,我向您展示了 firewalllaravelnuxt 的设置>nginxwebsockets。几天后,找到了解决办法:Laravel + Nuxt + Nginx: WebSocket is closed before the connection is established

    For comparison, see also the question itself on the link above.

    项目设置

    防火墙

    netstat -ntlp | grep 听

    root@dsde1032-21892:~# netstat -ntlp | grep LISTEN
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1066/nginx: master
    tcp        0      0 0.0.0.0:6001            0.0.0.0:*               LISTEN      7768/php
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1064/sshd
    tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1173/node
    tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      1066/nginx: master
    tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      1078/mysqld
    tcp6       0      0 :::22                   :::*                    LISTEN      1064/sshd
    

    lsof -i -P -n | grep 听

    root@dsde1032-21892:~# lsof -i -P -n | grep LISTEN
    sshd     1064     root    3u  IPv4  20044      0t0  TCP *:22 (LISTEN)
    sshd     1064     root    4u  IPv6  20138      0t0  TCP *:22 (LISTEN)
    nginx    1066     root    6u  IPv4  20168      0t0  TCP *:443 (LISTEN)
    nginx    1066     root    7u  IPv4  20169      0t0  TCP *:80 (LISTEN)
    mysqld   1078    mysql   31u  IPv4  20463      0t0  TCP 127.0.0.1:3306 (LISTEN)
    node     1173     root   18u  IPv4  20902      0t0  TCP 127.0.0.1:3000 (LISTEN)
    nginx    7402 www-data    6u  IPv4  20168      0t0  TCP *:443 (LISTEN)
    nginx    7402 www-data    7u  IPv4  20169      0t0  TCP *:80 (LISTEN)
    php      7768     root    5u  IPv4 110549      0t0  TCP *:6001 (LISTEN)
    

    ufw 状态

    root@dsde1032-21892:~# ufw status
    Status: active
    
    To                         Action      From
    --                         ------      ----
    OpenSSH                    ALLOW       Anywhere
    Nginx Full                 ALLOW       Anywhere
    6001                       ALLOW       Anywhere
    OpenSSH (v6)               ALLOW       Anywhere (v6)
    Nginx Full (v6)            ALLOW       Anywhere (v6)
    6001 (v6)                  ALLOW       Anywhere (v6)
    

    ufw 节目收听

    root@dsde1032-21892:~# ufw show listening
    tcp:
      22 * (sshd)
       [ 1] allow OpenSSH
    
      443 * (nginx)
       [ 2] allow 'Nginx Full'
    
      6001 * (php7.4)
       [ 3] allow 6001
    
      80 * (nginx)
       [ 2] allow 'Nginx Full'
    
    tcp6:
      22 * (sshd)
       [ 4] allow OpenSSH
    

    Laravel

    vim /var/www/api/config/websockets.php

    ...
        'apps' => [
            [
                'id' => env('PUSHER_APP_ID'),
                'name' => env('APP_NAME'),
                'key' => env('PUSHER_APP_KEY'),
                'secret' => env('PUSHER_APP_SECRET'),
                'path' => env('PUSHER_APP_PATH'),
                'capacity' => null,
                'enable_client_messages' => true,
                'enable_statistics' => false,
            ],
        ],
    ...
        'ssl' => [
            'local_cert' => '/etc/letsencrypt/live/larastart.site/fullchain.pem',
            'local_pk' => '/etc/letsencrypt/live/larastart.site/privkey.pem',
            'passphrase' => null,
            'verify_peer' => false
        ],
    ...
    

    vim /var/www/api/config/broadcasting.php

    ...
        'connections' => [
            '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'),
                    'useTLS' => true,
                    'encrypted' => false,
                    'host' => '127.0.0.1',
                    'port' => 6001,
                    'scheme' => 'https',
                    'curl_options' => [
                            CURLOPT_SSL_VERIFYHOST => 0,
                            CURLOPT_SSL_VERIFYPEER => 0,
                    ]
    
                ],
            ],
    ...
        ],
    ...
    

    努克斯

    vim /var/www/client/package.json

    {
      "name": "frontend",
      "version": "1.0.0",
      "private": true,
      "config": {
        "nuxt": {
          "port": "3000"
        }
      },
      "scripts": {
        "dev": "nuxt",
        "build": "nuxt build",
        "start": "nuxt start",
        "export": "nuxt export",
        "serve": "nuxt serve"
      },
      "dependencies": {
        "@nuxtjs/axios": "^5.12.2",
        "@nuxtjs/dotenv": "^1.4.1",
        "@nuxtjs/laravel-echo": "^1.1.0",
        "@nuxtjs/proxy": "^2.0.1",
        "nuxt": "^2.13.0",
        "pusher-js": "^4.4.0"
      },
      "devDependencies": {}
    }
    

    vim /var/www/client/plugins/echo.js

    import Echo from 'laravel-echo';
    
    export default (app) => {
        window.Pusher = require('pusher-js');
    
        window.Echo = new Echo({
            broadcaster: process.env.BROADCAST_DRIVER,
            key: process.env.PUSHER_APP_KEY,
            cluster: process.env.PUSHER_APP_CLUSTER,
    
            forceTLS: true,
            encrypted: false,
            wsHost: window.location.hostname,
            wsPort: 6001,
            wssPort: 6001,
            disableStats: true,
            enabledTransports: ['ws', 'wss']
        });
    }
    

    Nginx

    vim /etc/nginx/nginx.conf

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    include /etc/nginx/modules-enabled/*.conf;
    
    events {
            worker_connections 768;
            # multi_accept on;
    }
    
    http {
    
            ##
            # Basic Settings
            ##
    
            sendfile on;
            tcp_nopush on;
            types_hash_max_size 2048;
            # server_tokens off;
    
            # server_names_hash_bucket_size 64;
            # server_name_in_redirect off;
    
            include /etc/nginx/mime.types;
            default_type application/octet-stream;
    
            ##
            # SSL Settings
            ##
    
            ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
            ssl_prefer_server_ciphers on;
    
            ##
            # Logging Settings
            ##
    
            access_log /var/log/nginx/access.log;
            error_log /var/log/nginx/error.log;
    
            ##
            # Gzip Settings
            ##
    
            gzip on;
    
            # gzip_vary on;
            # gzip_proxied any;
            # gzip_comp_level 6;
            # gzip_buffers 16 8k;
            # gzip_http_version 1.1;
            # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    
            ##
            # Virtual Host Configs
            ##
    
            include /etc/nginx/conf.d/*.conf;
            include /etc/nginx/sites-enabled/*;
    }
    
    
    #mail {
    #       # See sample authentication script at:
    #       # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
    #
    #       # auth_http localhost/auth.php;
    #       # pop3_capabilities "TOP" "USER";
    #       # imap_capabilities "IMAP4rev1" "UIDPLUS";
    #
    #       server {
    #               listen     localhost:110;
    #               protocol   pop3;
    #               proxy      on;
    #       }
    #
    #       server {
    #               listen     localhost:143;
    #               protocol   imap;
    #               proxy      on;
    #       }
    #}
    

    vim /etc/nginx/sites-available/larastart.site

    server {
            server_name     larastart.site;
            root            /var/www/api/public;
    
            add_header X-Frame-Options              "SAMEORIGIN";
            add_header X-XSS-Protection             "1; mode=block";
            add_header X-Content-Type-Options       "nosniff";
    
            # Priority file extensions
            index index.php index.html index.htm index.nginx-debian.html;
    
            charset utf-8;
    
            # Check for the existence of files matching a provided url, forward to 404 if not found
            location /api {
                    try_files $uri $uri/ /index.php?$query_string;
            }
    
            # Serve static files directly
            location ~* ^/storage/(.*)\.(jpg|jpeg|gif|bmp|png|ico)$ {
                    access_log off;
            }
    
            location / {
                    proxy_pass                          http://127.0.0.1:3000;
                    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  $scheme;
                    proxy_set_header X-VerifiedViaNginx yes;
                    proxy_read_timeout                  300;
                    proxy_connect_timeout               300;
            }
    
            location /app {
                    proxy_pass             https://larastart.site:6001;
                    proxy_read_timeout     60;
                    proxy_connect_timeout  60;
                    proxy_redirect         off;
    
                    # Allow the use of websockets
                    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;
            }
    
            error_page 404 /index.php;
    
            # pass PHP scripts to FastCGI server
            location ~ \.php$ {
                    fastcgi_pass  unix:/var/run/php/php7.4-fpm.sock;
                    fastcgi_index index.php;
                    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
                    include fastcgi_params;
            }
    
            # deny access to .htaccess files, if Apache's document root concurs with nginx's one
            location ~ /\.(?!well-known).* {
                   deny all;
            }
    
            listen 443 ssl; # managed by Certbot
    
            ssl_certificate     /etc/letsencrypt/live/larastart.site/fullchain.pem;     # managed by Certbot
            ssl_certificate_key /etc/letsencrypt/live/larastart.site/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
    }
    
    server {
            if ($host = larastart.site) {
                    return 301 https://$host$request_uri;
            } # managed by Certbot
    
            listen 80;
            server_name larastart.site;
            return 404; # managed by Certbot
    }
    

    【讨论】:

      【解决方案2】:

      在我的情况下,将 pusher 从 6 降级到

      "pusher-js": "^4.3.1"
      

      它开始起作用了。 Javascript 我爱你! ?

      【讨论】:

      • 我应该把这个放在哪里或者我应该如何降级?我检查了 composer.json 但没有找到任何东西
      • pusher-js 它是一个 npm 包。你有它在 package.json
      【解决方案3】:

      所以在与ssl斗争了几天之后,我必须分享我在这个主题上的知识.. 根据文档安装后,websockets 与 http 一起使用,但在使用 ssl(443) 后没有。 我认为我的正确设置和 .pem 路径(让我们加密)有问题(我尝试了一切,这对我有用)。我在 VPS 服务器上使用带有端口 *:443 的 Apatche2 mydomain.conf 的正常设置。 websockets.php:

        'apps' => [
              [
                  'id' => env('PUSHER_APP_ID'),
                  'name' => env('APP_NAME'),
                  'key' => env('PUSHER_APP_KEY'),
                  'secret' => env('PUSHER_APP_SECRET'),
                  'enable_client_messages' => true,
                  'enable_statistics' => true,
                  'encrypted' => true,
              ],
          ],
        'ssl' => [ 
              'local_cert' => '/etc/letsencrypt/live/server1.mydomain.com/fullchain.pem',
              'local_pk' => '/etc/letsencrypt/live/server1.mydomain.com/privkey.pem', 
              'passphrase' => null,
              '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'),
                      'encrypted' => true,
                      'host' => 'server1.mydomain.com',
                      'port' => 6001,
                      'scheme' => 'https',
                      'curl_options' => [
                          CURLOPT_SSL_VERIFYHOST => 0,
                          CURLOPT_SSL_VERIFYPEER => 0,
                      ]
                  ],
              ],  
      
      Bootstrap.js:
        window.Echo = new Echo({
              auth:{ headers: { 'Authorization': 'Bearer ' + user.token } },
              broadcaster: 'pusher',
              key: process.env.MIX_PUSHER_APP_KEY,
              cluster: process.env.MIX_PUSHER_APP_CLUSTER,
              wsHost: window.location.hostname,
              wsPort: 6001,
              wssPort: 6001,
              disableStats: false, 
              enabledTransports: ['ws', 'wss']
       });
      

      我希望这会有所帮助。 谢谢,祝你好运,很快再见:)

      【讨论】:

      • 你是救生员,这终于对我有用了。为了让未来的读者更清楚 - 在你的 apache conf 文件中,你不需要使用代理传递或重写引擎到 ws:// 或 wss:// (如果套接字服务器由该虚拟主机提供服务) - 因此“我使用普通使用端口 *:443 的 Apatche2 mydomain.conf 的设置”为了证明概念,我将证书文件复制到 /config 目录并将它们归为 www-data。至于最终解决方案,您可以复制文件并在每次更新证书或授予文件权限时重新复制(符号链接似乎不起作用)。
      • 伙计,你救了我的命。这个答案是我一直在寻找的:)。谢谢你。
      【解决方案4】:

      通过在 websockets.php 中添加 ssl 路径解决了这个问题。我正在使用我在 Plesk 中添加的购买的 ssl。在 cli 中,证书的路径来自根目录:cd /usr/local/psa/var/certificates 然后我执行了“ls”来检查证书名称。在我的情况下,我使用带有私钥的证书并在 config/websockets.php 中添加为 local_cert 路径和 local_pk 路径

      最终设置:

      websockets.php

      'apps' => [
              [
                  'id' => env('PUSHER_APP_ID'),
                  'name' => env('APP_NAME'),
                  'key' => env('PUSHER_APP_KEY'),
                  'secret' => env('PUSHER_APP_SECRET'),
                  'path' => env('PUSHER_APP_PATH'),
                  'capacity' => null,
                  'enable_client_messages' => true,
                  'enable_statistics' => true,
              ],
          ],
      
       'ssl' => [
              /*
               * Path to local certificate file on filesystem. It must be a PEM encoded file which
               * contains your certificate and private key. It can optionally contain the
               * certificate chain of issuers. The private key also may be contained
               * in a separate file specified by local_pk.
               */
              'local_cert' => env('ssl_certificate', null),
      
              /*
               * Path to local private key file on filesystem in case of separate files for
               * certificate (local_cert) and private key.
               */
              'local_pk' => env('ssl_certificate_key', null),
      
              /*
               * Passphrase for your local_cert file.
               */
              'passphrase' => null,
              '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'),
                      'useTLS' => true,
                      'host' => '127.0.0.1',
                      'port' => 6004,
                      'scheme' => 'https',
                       'curl_options' => [
                          CURLOPT_SSL_VERIFYHOST => 0,
                          CURLOPT_SSL_VERIFYPEER => 0,
                      ]
                  ],
              ],
      

      bootstrap.js

      import Echo from 'laravel-echo'
      
      window.Pusher = require('pusher-js');
      
      window.Echo = new Echo({
          broadcaster: 'pusher',
          key: process.env.MIX_PUSHER_APP_KEY,
          wsHost: window.location.hostname,
          wsPort: 6004,
          wssPort: 6004,
          disableStats: true,
          cluster: process.env.MIX_PUSHER_APP_CLUSTER,
          encrypted: true
      });
      

      顺便说一句,当您更改 bootstrap.js 中的某些内容时,不要忘记运行 npm run dev 我在端口 6004 上运行它,所以如果你在 6001 上运行它,不要忘记更改我上面的设置

      【讨论】:

        【解决方案5】:

        您是否尝试过在“window.Echo”中使用这些选项?

         host:          window.location.hostname,
         httpHost:      window.location.hostname,
        

        【讨论】:

        • 这几天我看到了很多关于 Laravel Realtime 主题的问题.. 计划明天用 Laravel 6 制作一个指南或视频。如果它准备好了,我会把链接放在这里,但我希望你能在那之前找到解决方案..
        猜你喜欢
        • 1970-01-01
        • 2018-06-13
        • 1970-01-01
        • 2020-10-21
        • 2018-08-11
        • 1970-01-01
        • 2020-04-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多