FrankenPHP内置Mercure时,访问地址为https://www.php.cn/link/e925ccdfbd16ff62129653dcefd1745d;它集成在Caddy HTTP链中,不监听独立端口,路径固定,主机名由Caddyfile site定义,PHP同容器内可直接用localhost,需确保mercure指令启用且JWT密钥配齐。

FrankenPHP 内置 Mercure 时,访问地址就是 https://www.php.cn/link/e925ccdfbd16ff62129653dcefd1745d
FrankenPHP 启用 Mercure 后,它不是跑在独立端口(比如 :3000)上的外部服务,而是直接集成在 Caddy 的 HTTP 处理链中。所有 Mercure 请求都走标准 HTTP 路由,路径固定为 /.well-known/mercure,主机名取决于你 Caddyfile 中定义的 site。
- 如果 Caddyfile 是
localhost { ... },那发布地址就是<a href="https://www.php.cn/link/e925ccdfbd16ff62129653dcefd1745d">https://www.php.cn/link/e925ccdfbd16ff62129653dcefd1745d</a> - 如果配的是
myapp.test { ... },且本地 hosts 指向 127.0.0.1,则用<a href="https://www.php.cn/link/c80003e247c674c55ab68077fcfda4f4">https://www.php.cn/link/c80003e247c674c55ab68077fcfda4f4</a> - Docker 环境下 PHP 进程若和 FrankenPHP 在同一容器内(推荐),
localhost仍有效;若跨容器(不推荐),必须用容器名(如<a href="https://www.php.cn/link/c21646ec4a648c37d38249623f8f2c8c">https://www.php.cn/link/c21646ec4a648c37d38249623f8f2c8c</a>),并确保网络互通
不要试图改成 <a href="https://www.php.cn/link/8e5687e2d6ab87e5da2f833f3e8986a4">https://www.php.cn/link/8e5687e2d6ab87e5da2f833f3e8986a4</a> 或其他端口——FrankenPHP 内置 Mercure 不监听额外端口,也没有 --addr 参数可调。
用 curl 测试 Mercure 地址是否生效
最直接的验证方式是发一个 GET 请求看 discovery 响应:
- 运行
curl -v <a href="https://www.php.cn/link/e925ccdfbd16ff62129653dcefd1745d">https://www.php.cn/link/e925ccdfbd16ff62129653dcefd1745d</a> - 正确响应:HTTP 200 + JSON,含
{"hub":"...","subscriber":"..."}字段 - 常见错误:
-
404 Not Found:Caddyfile 中没启用mercure指令块,或该指令被注释 -
500 Internal Server Error:JWT 密钥为空、格式错误,或publisher_jwt和subscriber_jwt没配齐 -
Connection refused:FrankenPHP 根本没起来,或端口没映射对(Docker 下漏了-p 8000:8000)
-
注意:这个地址只用于发布(POST)和 discovery(GET),订阅端(EventSource)也必须用完全相同的 URL,不能加端口号、不能换协议(即不能用 https 除非你已配好 TLS)。
立即学习“PHP免费学习笔记(深入)”;
Symfony 或 Laravel 里怎么填 hub_url
框架配置里必须写成和实际请求路径完全一致的地址:
- 开发环境(FrankenPHP 本地运行):
hub_url: '<a href="https://www.php.cn/link/e925ccdfbd16ff62129653dcefd1745d">https://www.php.cn/link/e925ccdfbd16ff62129653dcefd1745d</a>' - 生产环境(通过域名访问):
hub_url: '<a href="https://www.php.cn/link/92de889f78c31fadd7efc7f01bf48c9a">https://www.php.cn/link/92de889f78c31fadd7efc7f01bf48c9a</a>'(前提是 Caddyfile 已配好 HTTPS 自动签发) - 绝对不要填
<a href="https://www.php.cn/link/467112cee2fcd913955a65c8cd322834">https://www.php.cn/link/467112cee2fcd913955a65c8cd322834</a>或<a href="https://www.php.cn/link/92cdc3666b7883ebeed2973e70725bb1">https://www.php.cn/link/92cdc3666b7883ebeed2973e70725bb1</a>—— 这是外部 Mercure 部署才用的地址,和 FrankenPHP 内置模式冲突
Symfony 的 config/packages/mercure.yaml 中若还保留 MERCURE_PUBLISH_URL 环境变量引用,要删掉;Laravel 的 .env 里同理清空相关变量。FrankenPHP 的 JWT 密钥来自 Caddyfile,不走环境变量。
为什么不能用反向代理改 Mercure 地址
有人想在 Caddyfile 里用 reverse_proxy 把 /.well-known/mercure 转到别的地方,这是徒劳的:
- FrankenPHP 的 Mercure 模块只响应它自己处理的路径,一旦被
reverse_proxy拦截,就绕过了内置 Hub -
mercure指令必须出现在 Caddyfile 的 site block 顶层,不能嵌套在路由规则里 - 若你真需要代理(比如前置 Nginx),那 Mercure 就不该用 FrankenPHP 内置,而该换成独立
dunglas/mercure容器 —— 二者不可混用
真正起作用的只有这一段(放在 Caddyfile 的 site block 内):
mercure {
publisher_jwt !ChangeThisMercureHubJWTSecretKey!
subscriber_jwt !ChangeThisMercureHubJWTSecretKey!
anonymous
}地址本身没有“配置项”,它是协议约定死的路径。你唯一能控制的,是这个路径绑定在哪个 host、是否启用 HTTPS、以及背后 JWT 密钥是否匹配。
复杂点在于:地址看似简单,但任何一环(Caddyfile 结构、JWT 字段、网络可达性、框架配置)出错,都会导致 /.well-known/mercure 表面通、实际拒收请求。调试时优先确认 curl GET 返回的是有效 JSON,再动 POST。



















