sse比websocket更合适礼物通知,因其天然支持自动重连、文本流分块和原生eventsource,而websocket需自行处理心跳、错误恢复等,增加复杂度;关键需正确设置content-type、utf-8编码、双换行结尾,并用serversentevents类异步推送。

Webman里用SSE推礼物通知,为什么比WebSocket更合适
因为礼物特效通知是典型的「服务器单向、高频率、低延迟、无需回执」场景。SSE天然支持自动重连、文本流分块、浏览器原生EventSource,而WebSocket要自己维护心跳、错误恢复、消息序列化,反而增加复杂度。
常见错误现象:EventSource频繁断连但控制台无报错;客户端收到重复消息;服务端推送后前端onmessage没触发——基本都是Content-Type或字符编码没对。
- 必须返回
text/event-stream,且全程保持UTF-8编码,任何BOM头或非UTF-8字符都会中断流 - 每条消息结尾必须带双换行
\n\n,单个\n会被忽略 - 服务端不能关闭连接(除非业务逻辑明确结束),否则客户端3秒后自动重连,可能造成消息重复
如何在Webman控制器中正确构造SSE响应
关键不是“怎么写”,而是“怎么不阻塞”。Webman默认协程模型下,直接在HTTP响应里循环echo会卡住整个worker。必须用ServerSentEvents类配合异步定时器,把推送逻辑从主请求生命周期剥离。
实操建议:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 不要在
Response对象里手动write,改用Workerman\Protocols\Http\ServerSentEvents实例 - 每个直播间对应一个独立的SSE连接,用
live_id做路由标识,避免混推 - 推送前检查客户端是否还在线:
$connection->isClosed(),否则协程会堆积 - 示例片段:
use Workerman\Protocols\Http\ServerSentEvents;<br>$sse = new ServerSentEvents($connection);<br>$sse->send(['type' => 'gift', 'data' => $giftPayload], 'gift_event');
礼物消息广播性能瓶颈在哪,怎么绕过
单直播间万人同时在线时,用foreach遍历所有连接调用$connection->send()会瞬间打满CPU和内存。这不是代码写得不够优雅,是架构层级问题。
必须放弃“服务端主动推给所有人”的思路:
- 改用Redis Pub/Sub:礼物事件先发到
channel:gift:{live_id},每个SSE连接只订阅自己关注的频道 - 用
ServerSentEvents::broadcast()替代手动遍历,它内部做了协程批处理和缓冲区优化 - 对非实时要求的礼物(如点赞数聚合),走离线计算+定时拉取,不挤占SSE带宽
- 限制单次推送数据量:SVG 3D礼物只传ID和参数,资源由前端按需加载,不走SSE流
前端EventSource怎么避免重复初始化和内存泄漏
页面切换、组件卸载时忘记eventSource.close(),会导致连接堆积、内存持续上涨,最终触发浏览器最大连接数限制(Chrome默认6个同源SSE)。
真实开发中容易被忽略的点:
- 用
ref或useState存EventSource实例,组件卸载时显式.close() - 监听
onerror并判断eventSource.readyState === 0,这是重连开始的信号,不是错误 - 不要用
new EventSource('/api/gift-sse?live_id=xxx')拼接URL,改用URLSearchParams确保参数编码正确 - 调试时加
console.log('SSE connected:', eventSource.url),确认每次打开都是新连接而非复用










