mercure适合服务端单向推送场景,基于http/2 sse实现自动重连、断线续传与鉴权;websocket适合双向高频交互,需自行管理心跳、重连与广播,二者在frankenphp中分层共存。

Mercure 和 WebSocket 在 FrankenPHP 中解决的是不同层级的问题:前者是基于 HTTP/2 Server-Sent Events(SSE)的标准化推送协议,后者是底层双向通信通道。选哪个不取决于“谁更先进”,而取决于你是否需要客户端主动发消息、是否接受单向语义、以及是否愿意自己管理连接生命周期。
Mercure 适合「服务端推、客户端只收」的场景
Mercure 的核心是标准 HTTP 推送:服务端通过 Publish API 向一个或多个主题发布更新,客户端用浏览器原生的 EventSource 订阅,自动重连、按 Last-Event-ID 断线续传。
- 常见错误现象:
WebSocket被强行用来做纯通知推送,结果要自己写心跳、重连、消息去重、连接状态同步,最后发现 80% 的代码都在补Mercure已经内置的能力 - 使用场景:后台系统通知、实时仪表盘数据刷新、文章更新提醒、日志流展示
- 关键优势:
- 不需要客户端 JavaScript 写连接管理逻辑,
new EventSource('/.well-known/mercure?topic=...')一行搞定 - 自动处理跨域、HTTPS、HTTP/2 多路复用,和 Nginx / CDN 兼容性极好
- 支持 JWT 鉴权、主题粒度权限控制(如
@#@#@#@#@#@#@#@#@#@0})
- 不需要客户端 JavaScript 写连接管理逻辑,
- 注意事项:
- 客户端无法通过同一连接发送数据;想回传操作(比如“已读”、“点赞”),得另发普通 HTTP 请求
- 消息必须是 UTF-8 文本;不适合传二进制或大块数据(如图片 base64)
WebSocket 适合「双向高频、低延迟、自定义语义」的交互
FrankenPHP 的 Worker 模式让 PHP 能长期驻留内存,因此可以原生启动 WebSocket 服务(例如用 Swoole 或 ReactPHP 集成),但你要承担全部连接治理成本。
- 常见错误现象:用
WebSocket推送系统通知,却忽略浏览器标签页切换后连接静默断开、移动端后台被杀、Nginx 默认 60 秒空闲超时等问题,线上表现为“偶尔收不到第一条消息” - 使用场景:在线协作文档、实时游戏指令、客服打字状态、白板协作、需要客户端实时反馈的操作(如拖拽坐标、语音输入状态)
- 关键差异:
- 必须自行实现心跳(
ping/pong帧)、重连退避、连接 ID 映射、多实例广播(靠 Redis Pub/Sub 或消息队列中转) - 可以自定义二进制帧、压缩传输、消息 ACK、会话上下文绑定(如用户 ↔ 连接 ↔ 房间)
- 协议无标准业务语义:发一个
{"type":"join","room":"abc"},服务端必须自己解析、校验、路由——Mercure不管这些
- 必须自行实现心跳(
- 性能影响:
-
WebSocket单连接带宽更低(无 HTTP Header),但每个连接占用一个 PHP Worker 进程/协程,高并发下资源消耗更敏感 -
Mercure基于 HTTP/2 流,一个 TCP 连接可复用多个推送流,更适合海量轻量订阅
-
FrankenPHP 下二者共存不是妥协,而是分层
很多项目最终都走向混合架构,因为真实业务从来不是非此即彼:
- 用
Mercure推送广播类消息(如“新版本上线”、“系统维护通知”、“某用户被踢出群”) - 用
WebSocket处理点对点或房间内强交互(如“发送聊天消息”、“共享光标位置”、“协同编辑 OT 操作”) - 二者共享同一套鉴权逻辑(如 JWT 解析)、同一套用户状态存储(如 Redis),但协议层完全解耦
最易被忽略的一点:Mercure 的 Hub 是可选组件,而 WebSocket 的服务端是你必须从零搭起的基础设施。在 FrankenPHP 里启用 Mercure 只需几行配置和一个 JWT 密钥;而跑稳一个生产级 WebSocket 服务,你得盯住连接数泄漏、内存缓慢增长、进程异常退出、SSL 握手失败率——这些不会出现在 demo 里,只会在凌晨三点的告警里出现。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











