SSE仅支持服务端到浏览器的单向通信,无法直接同步客户端消息发送状态;需用HTTP POST发送消息并管理ID与超时,SSE仅用于接收服务端推送的状态更新。

JavaScript 中 SSE(Server-Sent Events)本身是单向的(服务端 → 浏览器),不支持客户端主动发送消息,所以“消息发送状态”的同步不能靠 SSE 直接完成。真正要实现“用户点击发送 → UI 显示发送中/成功/失败”,需要结合其他机制——SSE 仅适合推送服务端产生的后续状态(如对方已读、消息被持久化、投递结果等)。关键在于:把“发送动作”和“状态更新”拆开处理。
1. 发送消息走 HTTP POST(或 WebSocket),SSE 仅负责接收状态
用户点击发送时,用 fetch 或 axios 发起一次普通请求提交消息内容。此时 UI 立即进入“发送中”态(比如禁用按钮、显示 loading 图标):
- 请求发出后,前端生成唯一消息 ID(如
crypto.randomUUID()),并存入本地状态(如 React 的useState或全局 Map) - 同时启动一个超时逻辑(例如 8 秒未收到确认则标记为“发送失败”)
- SSE 连接保持打开,监听服务端广播的事件,其中包含该消息 ID 对应的状态(如
{"id": "msg_abc", "status": "sent"})
2. 服务端需按消息 ID 主动推送状态事件
SSE 响应体必须符合规范:每条事件以 data: 开头,可选 id: 和 event:。服务端在消息处理各阶段(接收成功、写入 DB、推送给对方、对方回执)主动向该用户推送带 ID 的事件:
id: msg_abc
event: message_status
data: {"status":"received","timestamp":1715823400}
前端用 EventSource 监听 message_status 事件,并根据 event.id 匹配本地待更新的消息项,更新 UI 状态(如将“发送中”改为绿色对勾)。
立即学习“Java免费学习笔记(深入)”;
3. 处理丢失、乱序与重复事件
SSE 天然支持自动重连和事件 ID 续传,但业务上仍需防护:
- 前端收到事件时,先检查
event.id是否存在于本地待确认列表中,避免处理过期消息 - 服务端推送状态时带上时间戳,前端跳过比当前已知状态更旧的事件(用
Math.max更新) - 对“成功”“失败”等终态事件,收到后立即从本地状态中移除对应 ID,防止重复更新
4. 错误降级与用户体验补全
纯 SSE 无法感知网络中断或服务端宕机。建议补充:
- 监听
eventsource.onerror,触发重试逻辑或提示“连接异常,部分状态可能延迟” - 对超时未确认的消息,提供“重新发送”按钮,而不是无限等待
- 若业务允许,服务端可在 SSE 断连恢复后,批量补推最近 5 条未确认消息的最终状态(通过首次连接时携带 last-event-id 或额外查询接口)
不复杂但容易忽略:SSE 不是万能管道,它只解决“服务器通知前端”这一半;发送动作、ID 管理、超时控制、错误反馈,都得前端自己闭环。把职责分清,UI 同步就稳了。


















