FrankenPHP 原生集成 Mercure,作为编译进二进制的 HTTP/2 SSE+JWT 推送服务,无需独立部署;其内置 Caddy 直接解析 mercure 指令,Go 层 Hub 处理发布/订阅,PHP 通过 localhost 路径发布事件,与应用共享内存和生命周期。

Mercure 在 FrankenPHP 里是原生集成的,不是可选插件,而是编译进二进制的 HTTP/2 Server-Sent Events(SSE)+ JWT 认证推送服务。所以 Symfony 不需要、也不应该再单独部署 Mercure Hub —— 启用后它就跑在 FrankenPHP 进程里,和 PHP 应用共享内存与生命周期。
FrankenPHP 的 Mercure 是怎么工作的
它不是调用外部 mercure 二进制,也不是反向代理到另一个端口。FrankenPHP 内置的 Caddy 实例直接解析 mercure 指令块,把发布/订阅请求交给 Go 层的内置 Hub 处理。PHP 侧通过 curl 或 file_get_contents 向 http://localhost/.well-known/mercure(或你配的路径)发 POST 就能发布事件,完全绕过网络栈。
Symfony 配 Mercure 时必须改掉的三件事
- 删掉
docker-compose.yml里独立的mercureservice 块,否则端口冲突(FrankenPHP 默认占:80/:443,Mercure Hub 会抢:3000) - 注释或删除
.env中的MERCURE_PUBLISH_URL和MERCURE_JWT_KEY—— FrankenPHP 用的是内置密钥,由CADDYFILE里的mercure指令控制 - 不要在 Symfony 的
config/packages/mercure.yaml里写hub_url;FrankenPHP 模式下应设为hub_url: 'http://localhost/.well-known/mercure',且仅用于开发环境 fallback
配置示例:Caddyfile 里启用 Mercure 并对接 Symfony
your-domain.com {
mercure {
publish_origins ["https://your-domain.com"]
# JWT 密钥由 FrankenPHP 自动生成,无需手动指定
# 如果要自定义,用 environment 变量 MERCURE_JWT_KEY(不推荐)
cors_origins ["https://your-domain.com"]
}
<pre class="brush:php;toolbar:false;">php_server {
# Symfony 的 public/ 已被移至根目录,index.php 自动接管
# 不需要额外 fastcgi_pass 或 proxy_pass
}}
注意:publish_origins 必须显式声明,否则 Symfony 的 MercureBundle 发布时会因 CORS 被拒;cors_origins 控制前端订阅是否被允许。
容易被忽略的坑:缓存与 HTTPS 重定向
FrankenPHP 默认开启自动 HTTPS,但 Mercure 的 SSE 流依赖长连接,若你在 Caddyfile 里写了 redir https://{host}{uri} permanent,会导致前端订阅请求被 301 重定向中断 —— SSE 不支持重定向续连。正确做法是让 HTTP 和 HTTPS 共存,或确保 Mercure endpoint 始终走 HTTPS(即只监听 :443),并在 mercure 块中配好 publish_origins 为 https://...。
FrankenPHP 的 Mercure 不是“兼容层”,它是运行时的一部分。一旦开了,就别把它当外部服务去运维 —— 它没有独立日志、没有单独健康检查端点、也不能用 systemctl restart mercure 管控。所有行为都受 Caddyfile 和 FrankenPHP 启动参数约束。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











