根本原因是后端未运行websocket服务或配置错位:laravel自身不提供websocket服务器,必须手动执行php artisan websockets:serve并确保其持续运行,同时严格对齐wshost(禁用localhost,改用127.0.0.1或真实ip)、wsport(默认6001)、pusher_app_key(前后端完全一致)、nginx代理头(proxy_http_version 1.1、upgrade、connection)及频道名格式(如.private-user.123)。

WebSocket 连不上,laravel-echo 一直显示 connecting
根本原因不是前端代码写错了,而是后端压根没跑起来或配置错位。Laravel 自身不提供 WebSocket 服务器,php artisan websockets:serve 必须在后台持续运行,且不能被防火墙、Docker 网络或 Nginx 拦截。
常见卡点:
-
wsHost写成localhost—— 某些浏览器(尤其 Chrome)和 Docker 容器内会解析失败,改用127.0.0.1或服务实际 IP -
wsPort默认是6001,不是80或443;若改了端口,前端wsPort和启动命令的--port必须一致 - Nginx 反向代理时漏配关键头:
proxy_http_version 1.1、Upgrade $http_upgrade、Connection "upgrade" - 环境变量
PUSHER_APP_KEY在config/broadcasting.php(pusher 驱动)和config/websockets.php(apps.0.key)里必须完全一致,不能一个是local一个是app-key-123
广播事件发了,但前端收不到
不是队列没跑,也不是事件没触发,而是「频道名 + 事件名」双校验断在任意一环就静默失败。
检查顺序:
- 事件类是否实现
ShouldBroadcast,且broadcastOn()返回的是PrivateChannel('user.123')或Channel('public'),不是字符串 - 前端监听频道名必须严格匹配:后端返回
PrivateChannel('user.123'),前端就得用.private-user.123(开头带点),不能写成user.123或.user.123 - 如果用了
broadcastAs(),比如返回'notification.new',前端.listen('notification.new', ...)才有效;否则默认按类名App.Events.NotificationNew匹配,大小写和命名空间都不能错 - 队列驱动不是
sync的话,php artisan queue:work必须正在运行;Redis 队列还要确认QUEUE_CONNECTION=redis和BROADCAST_DRIVER=redis已启用
私有频道认证失败,换账号就收不到通知
私有频道(PrivateChannel)和存在频道(PresenceChannel)必须走 routes/channels.php 的授权逻辑,这里写错就直接拒绝连接,连握手都过不去。
典型问题:
- 闭包里没 return true/false,或者用了
Auth::check()却没处理 guest 状态 - 频道名硬编码,比如
Route::channel('user.{id}', function ($user, $id) { return $user->id == $id; });,但事件里传的是auth()->id(),而用户未登录时auth()->id()是 null,导致路由匹配失败 - 中间件没生效,比如在
channels.php里用了auth:sanctum,但请求没带Authorization: Bearer xxx或 cookie 未正确传递 - 前端初始化 Echo 时没传
auth配置,比如缺了csrfToken或authEndpoint,导致鉴权请求 403
本地开发能通,上线后通知延迟或丢消息
单机 websockets:serve 在生产环境扛不住并发,也做不到多实例状态同步,必须切到 Redis 模式。
关键配置项(config/websockets.php):
-
'replication' => ['mode' => 'redis']启用跨进程同步 -
'apps' => [['capacity' => 10000]]设置单应用最大连接数,避免被踢 -
'statistics' => ['enable' => true]打开统计,配合仪表盘/laravel-websockets查实时连接数和错误率 - 确保 Redis 服务稳定,
redis-cli ping能通,且 PHP 的redis扩展已启用(不是 predis)
真正容易被忽略的是:WebSocket 连接是长生命周期的,一旦某个实例宕机,已连客户端不会自动漂移——得靠负载均衡层做健康检查 + 会话保持,否则用户会掉线。











