根本原因是广播链路断在驱动层:必须设broadcast_driver=pusher、配置pusher驱动指向127.0.0.1:6001且usetls=false,否则事件无法离开laravel进程。

为什么 Laravel WebSockets 启动了却收不到事件
根本原因不是服务没跑起来,而是广播链路断在了驱动层。运行 php artisan websockets:serve 只是起了个 WebSocket 服务进程,它不会自动接收 Laravel 的广播事件——Laravel 还得知道“把事件往哪儿发”。
必须同时满足三项配置:
- BROADCAST_DRIVER=pusher(不能是 redis 或 log)
- config/broadcasting.php 中 connections.pusher.options.host 指向本地服务地址(如 127.0.0.1),端口为 6001
- options.useTLS 在开发环境设为 false,否则浏览器因自签名证书拒绝连接
不改驱动,哪怕 WebSocket 进程在跑,事件也压根不会离开 Laravel 进程。
PrivateChannel 订阅卡在 connecting 的真实原因
前端调用 Echo.private('user.123') 后,Laravel 会自动发起 POST 请求到 /api/broadcasting/auth,这个请求失败,前端就永远停在 connecting 状态。
排查要点:
- App\Providers\BroadcastServiceProvider 必须在 config/app.php 的 providers 数组中启用(取消注释)
- routes/channels.php 对应频道闭包必须返回 true 或含 auth 字段的数组,不能返回空数组、字符串或 null
- 鉴权接口响应体必须是标准 JSON,且严格包含 auth 字段,例如 {"auth":"v8Z:Ym"};返回 {"error": "unauthorized"} 会导致前端静默失败
- 前端 authEndpoint 地址必须与后端应用域名/协议完全一致,跨域或 http/https 不匹配会触发 CORS 或 404
队列任务进度推送为什么不能直接 dispatch()
dispatch() 只负责把任务塞进队列,它不参与执行过程,更不感知进度。想实时推进度,必须让任务自己“发声”。
正确做法是:
- 任务执行中,用 Redis::set("job:progress:{$uuid}", $percent) 写状态(别用数据库主表,高并发 UPDATE 会拖垮队列消费)
- 同时触发广播事件:broadcast(new JobProgressUpdated($uuid, $percent)),事件类需实现 ShouldBroadcast
- 频道必须是 public 类型(ProgressChannel 中 join() 返回 true),private 或 presence 需鉴权,不适合通用进度通道
- 前端用 Echo.channel('progress.' . jobId) 订阅,频道名必须和事件 broadcastOn() 返回值逐字符一致
前端收不到事件?先核对这三处大小写与拼接
频道名是敏感字符串,差一个点、空格、大小写或数据类型都会导致订阅失败。
常见陷阱:
- 事件类里 return new Channel('chat-room'),前端写了 Echo.channel('chat_room') → 失败
- new PrivateChannel('user.' . $id) 中 $id 是整数 123,但前端传参是字符串 "123" → 实际频道名不同(PHP 字符串拼接对类型敏感)
- .env 中的 PUSHER_APP_CLUSTER 填错(比如新 Pusher 应用该填 mt1 却填成 us2),连接静默失败,控制台无报错
- 前端 JS 读不到 PUSHER_APP_KEY,因为未加 MIX_ 前缀,实际应写 MIX_PUSHER_APP_KEY 并经 Laravel Mix 注入
最易被忽略的是:每次改完 .env 后必须手动运行 php artisan config:clear,缓存不清理,所有配置改动都无效。











