JavaScript无法连接Laravel+Ratchet搭建的安全WebSocket服务器求助
开发环境
- OS: Microsoft Windows 10
- PHP框架: Laravel 8.0
- PHP版本: 7.4
- Websocket服务端: cboden/ratchet 0.4.3
- 集成环境: WAMP server 3.2.0 (Apache 2.4.41)
- 测试浏览器: Firefox 91.0.1 (64位) / Chrome
问题说明
我新建了一个Laravel应用来实现安全WebSocket服务端,客户端侧(Laravel blade文件)使用原生JavaScript发起连接。目前WebSocket服务端运行状态正常,但浏览器无法成功建立连接,报错截图如下:
我已尝试使用带端口、不带端口的不同URL连接,均未生效。我使用openssl.exe工具生成了SSL证书和私钥文件,放置在命令执行目录下用于测试。
安全WebSocket服务端handle方法代码
public function handle() { $loop = Factory::create(); $webSock = new SecureServer( new Server('0.0.0.0:8090', $loop), $loop, array( 'local_cert' => 'certificate.crt', 'local_pk' => 'private.key', 'allow_self_signed' => TRUE, 'verify_peer' => FALSE ) ); // Ratchet逻辑 $webServer = new IoServer( new HttpServer( new WsServer( new WebSocketController() ) ), $webSock ); $loop->run(); }
httpd-ssl.conf虚拟主机配置
<VirtualHost *:443> ServerName ssa DocumentRoot "d:/web/app/ssa/public" SSLEngine on SSLCertificateFile "${SRVROOT}/conf/certificate.crt" SSLCertificateKeyFile "${SRVROOT}/conf/private.key" SSLVerifyClient none SSLVerifyDepth 10 <Directory "d:/web/app/ssa/public"> Options +Indexes +Includes +FollowSymLinks +MultiViews AllowOverride All Require local </Directory> ProxyRequests Off ProxyPass /wss/ ws://ssa:8090 </VirtualHost>
目前Apache的proxy_module、proxy_http_module、proxy_wstunnel_module模块均已启用,站点运行在HTTPS协议下。此前站点运行在HTTP+WS协议时所有功能正常,升级为HTTPS后出现WSS连接失败问题,请问我是否遗漏了相关配置?我的WebSocket服务端或Apache配置存在什么问题?
问题排查与解决方案
你当前的配置存在两处核心冲突,还有部分遗漏配置,按以下步骤修改即可修复:
- 移除Ratchet端的SSL配置
你用Apache做WSS反向代理的场景下,不需要让Ratchet本身处理SSL加密,直接把Ratchet改成普通WS服务即可,由Apache统一做SSL卸载,修改handle方法代码:
public function handle() { $loop = Factory::create(); // 去掉SecureServer封装,直接用普通Server $webSock = new Server('0.0.0.0:8090', $loop); // Ratchet逻辑保持不变 $webServer = new IoServer( new HttpServer( new WsServer( new WebSocketController() ) ), $webSock ); $loop->run(); }
- 完善Apache反向代理配置
你当前的ProxyPass缺少WebSocket协议升级的必要头配置,还有反向代理的回退规则,修改httpd-ssl.conf里的代理部分配置:
ProxyRequests Off # 开启WebSocket代理的头识别 RewriteEngine on RewriteCond %{HTTP:Upgrade} =websocket [NC] RewriteCond %{HTTP:Connection} upgrade [NC] RewriteRule ^/wss/(.*) ws://ssa:8090/$1 [P,L] ProxyPass /wss/ ws://ssa:8090/ ProxyPassReverse /wss/ ws://ssa:8090/
修改后重启Apache服务,重启Ratchet的WebSocket服务。
3. 客户端连接地址确认
客户端直接连接wss://你的站点域名/wss/即可,不要加8090端口,所有请求走Apache的443端口代理即可。
如果确实需要让Ratchet本身处理SSL(不经过Apache代理直接对外暴露WSS端口),再做以下修改:
- 把Apache的代理配置删除,客户端直接连接
wss://你的域名:8090 - 确认你执行Laravel命令启动WebSocket服务的工作目录下,确实存在certificate.crt和private.key文件,避免相对路径读取失败
- 提前在浏览器里访问一次
https://你的域名:8090,确认自签证书已经被浏览器信任,再发起WebSocket连接。
内容的提问来源于stack exchange,提问作者jgarcias
相关产品推荐
相关产品推荐

