PHP-Mercure(php-mercure)仅是轻量客户端库,不提供Hub服务,需已部署并配置好Mercure Hub(如Docker镜像或Caddy+Mercure),且PHP≥8.0、启用ext-curl;它只负责构造JWT认证的POST发布请求和SSE订阅URL,不处理连接保活或EventSource解析。

确认 PHP-Mercure 是否适配当前项目架构
PHP-Mercure 本身不是官方 Mercure 实现,而是社区维护的轻量客户端库(php-mercure),仅负责生成 JWT 认证 URL、发布事件到 Mercure Hub,不提供 Hub 服务。如果你误以为它能替代 Symfony 的 mercure bundle 或独立 Hub 进程,后续会卡在“消息发不出去”或“订阅无响应”上。
实际使用前提是:你已有运行中的 Mercure Hub(如官方 Docker 镜像、Symfony 内置 Hub 或自建 Caddy + Mercure 模块),且该 Hub 已配置好 JWT 密钥和允许的发布/订阅域。
-
php-mercure只做两件事:构造带Authorization头的 POST 请求、拼接带topic参数的 SSE 订阅 URL - 它不处理连接保活、重连、EventSource 自动解析,这些得前端自己写或用
mercurepolyfill - 若项目是 Laravel,优先考虑
symfony/mercure-bundle;纯 PHP 项目才用php-mercure
用 Composer 安装并验证基础依赖
执行 composer require php-mercure/php-mercure 后,检查是否自动加载了 ext-curl —— 这个库所有 HTTP 请求都走 cURL,没启用会直接抛 Class 'CurlHandle' not found 错误。
别跳过环境检查:
立即学习“PHP免费学习笔记(深入)”;
- PHP 版本需 ≥ 8.0(低版本会因
Typed property报错) - 若用
file_get_contents替代 cURL(极不推荐),需手动 patchPhpMercure\Client的send()方法,但官方不支持 - 安装后运行
composer show php-mercure/php-mercure确认版本为^0.4或更高(0.3有 JWT 时间戳校验 bug)
正确初始化 Client 并构造带 JWT 的发布请求
JWT 是 Mercure Hub 验证发布权限的关键,php-mercure 不生成密钥也不管理 JWT,必须你自己用 firebase/php-jwt 或 namshi/jose 生成 token,再传给 PhpMercure\Client。
常见错误是把 Hub 地址写成 http://localhost:3000/.well-known/mercure —— 这是发现端点,发布地址应是 http://localhost:3000/.well-known/mercure(没错,路径一样,但 POST 到这里)。
- Hub URL 末尾不能带斜杠,否则
Client会拼出//导致 404 - JWT 必须含
mercure声明,例如:{"mercure": {"publish": ["https://example.com/books/*"]}} - 发布数据必须是字符串,不是数组 ——
json_encode($data)得自己做,库不帮你序列化 - 示例关键片段:
$client = new \PhpMercure\Client('http://localhost:3000/.well-known/mercure', $jwt); $client->publish(['id' => 'book-123'], 'https://example.com/books/123');
前端订阅时注意 topic 匹配与 CORS 配置
PHP 端发布的 topic(如 https://example.com/books/123)必须和前端 EventSource 的 URL 中 topic 参数完全一致,大小写、协议、路径都不能差 —— Mercure Hub 默认严格匹配,不支持通配符回退。
典型坑是开发环境用 http://localhost,但 Hub 的 ALLOWED_ORIGINS 没加这个域名,导致浏览器报 Failed to start event source 而非明确 CORS 错误。
- Hub 启动时确保设置了
-allow-origin="http://localhost:8000"(对应你的前端地址) - 前端订阅 URL 示例:
new EventSource("http://localhost:3000/.well-known/mercure?topic=https%3A%2F%2Fexample.com%2Fbooks%2F123") - 如果 topic 是动态生成的,务必对 URI 组件做
encodeURIComponent(),否则斜杠会被截断 - Chrome 控制台 Network 标签里看
.well-known/mercure请求状态码:200 才算连上,502/401 表示 Hub 配置或 JWT 问题
真正麻烦的从来不是装包或发请求,而是 Hub 的 JWT 验证链路断在哪一环 —— JWT 过期、密钥不匹配、topic 权限不足、CORS 白名单漏写、甚至 Hub 日志默认不输出验证失败详情。建议先用 curl 手动发一个带正确 JWT 的 POST,确认 Hub 能接收,再让 PHP 代码介入。



















