超越代码 Laravel Websockets:failed:WebSocket在连接建立之前关闭

9
在本地,WebSockets 运行得很好,但是在生产环境中,我一直收到标题中的错误。一些背景信息,我正在使用 WebSockets 包:beyondcode/laravel-websockets。我正在使用监控程序运行“php artisan websockets:serve --port=6004”,并确保端口 6004 是开放的。在生产环境中,我尝试了带 SSL 和不带 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,
                ]
            ],
        ],

我的WebSocket设置:

'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设置:

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

    ],

7个回答

14

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

"pusher-js": "^4.3.1"

它开始工作了。Javascript我爱你!


我应该把这个放在哪里或者如何降级?我查看了composer.json文件,但没有找到任何内容。 - Saddan
1
pusher-js是一个npm包。你可以在package.json中找到它。 - rafael

13

所以经过几天与SSL的搏斗后,我必须分享我的知识。按照文档安装后,WebSockets可以使用HTTP正常工作,但在使用SSL(443)后不行。我认为我在正确的设置和.pem路径(Let's Encrypt)上遇到了问题(我尝试了一切,这对我有用)。我在VPS服务器上使用Apache2 mydomain.conf的普通设置,端口号为*:443。

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配置文件中,如果套接字服务器由该虚拟主机提供,则不需要使用代理传递或重写引擎到ws://或wss:// - 因此“我使用Apatche2 mydomain.conf的常规设置,端口*:443”。为了证明概念,我将证书文件复制到/config目录并将其chowned为www-data。至于最终解决方案,您可以复制文件并在每次更新证书或授予权限时重新复制文件(符号链接似乎无法工作)。 - Sethmo011
哥们,你救了我的命。这个答案就是我在找的!谢谢你!!! - GianPierre Gálvez

3
我也曾面临这个问题,并发布了一个更详细的问题,其中展示了有关防火墙、Laravel、Nuxt、Nginx和Websockets的设置。 几天后,找到了解决方案:Laravel + Nuxt + Nginx: WebSocket is closed before the connection is established 为了比较,请参见上面链接中的问题本身。
项目设置
防火墙
netstat -ntlp | grep LISTEN
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 LISTEN

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)

显示正在监听的端口号。
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,
                ]

            ],
        ],
...
    ],
...

Nuxt

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

编辑 /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

我在我的实际服务器上也遇到了这个问题。对于我来说,它无法正常工作是因为我的端口不被允许。输入sudo ufw allow 6001命令后,我的实际服务器开始正常工作。在此处输入图片说明


1
这确实是我的问题,谢谢你的提示! - PassionCorner

1

通过在websockets.php中添加ssl路径来解决了问题。我正在使用购买的ssl,将其添加到了Plesk中。在cli中,证书路径是从根目录开始的:cd /usr/local/psa/var/certificates,然后我执行了'ls'来检查证书名称。在我的情况下,我使用了带有私钥的证书,并将其作为本地_cert路径和本地_pk路径添加到config/websockets.php中。

最终设置:

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上运行它,请不要忘记在我的上面设置中更改它。


1

使用 Laravel 10、Vue3 和 Pusher-js 7.6 升级到 2023 年。

将以下配置放入代码中,然后您就可以开始使用了:

在 bootstrap.js 中:

import Echo from 'laravel-echo';
import pusherJs from 'pusher-js'
window.Pusher = pusherJs

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'local',
    wsHost: window.location.hostname,
    wsPort: 6001,
    wssPort: 6001,
    cluster : 'mt1',
    forceTLS: false,
    encrypted: true,
    disableStats: true,
    enabledTransports: ['ws', 'wss'],
});

在 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' => '127.0.0.1',
                'port' => 6001,
                'scheme' => 'http'
            ],
        ],

在 .env 文件内

PUSHER_APP_ID=local
PUSHER_APP_KEY=local
PUSHER_APP_SECRET=local
PUSHER_APP_CLUSTER=mt1
BROADCAST_DRIVER=pusher
SESSION_DRIVER=file

0

你尝试过在 "window.Echo" 中使用这些选项吗?

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

最近我看到很多关于Laravel实时主题的问题..打算明天用Laravel 6制作一个指南或视频。如果准备好了,我会在这里放链接,但我希望你们在那之前就能找到解决方案.. - boolfalse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接