
本文详解 symfony 应用通过 hubinterface 向本地 caddy mercure hub 推送更新时出现 “failed to send an update” 错误的根本原因(ssl 证书验证失败),并提供安全、可落地的配置修复方案。
在本地开发环境中使用 Symfony 集成 Mercure(尤其是搭配 Caddy 作为 Hub)时,常见报错如下:
Failed to send an update SSL certificate problem: unable to get local issuer certificate for "https://localhost/.well-known/mercure"
或 PHP 原生调用 file_get_contents() 时触发警告:
Warning: file_get_contents(https://localhost/.well-known/mercure): Failed to open stream: operation failed
而终端 curl 命令却能成功 —— 这明确指向 PHP HTTP 客户端的 TLS 证书验证机制,而非 Mercure 或 JWT 配置本身。
根本原因分析
Caddy 在开发模式下(如 Caddyfile.dev)默认使用自签名证书提供 HTTPS 服务(例如 https://localhost)。Symfony 的 HubInterface 底层依赖 HttpClientInterface(通常由 Symfony HttpClient 组件实现),该客户端默认启用严格的 SSL 证书验证(verify_peer: true)。当证书非由受信 CA 签发(如自签名或本地 Caddy 生成的证书)时,PHP 拒绝建立连接,导致推送失败。
值得注意的是:curl 命令行工具默认不校验证书(除非显式加 -k 或配置 --cacert),因此能绕过此限制;而 PHP 的 file_get_contents() 在启用了 allow_url_fopen 且未配置 ssl 上下文时,同样可能因 OpenSSL 默认策略拒绝不信任证书。
✅ 推荐解决方案:禁用开发环境 SSL 验证(仅限本地)
在 config/packages/framework.yaml 中为 HTTP 客户端配置放宽证书校验:
# config/packages/framework.yaml
framework:
http_client:
default_options:
verify_peer: false
# 可选:同时禁用主机名验证(若证书 CN 不匹配 localhost)
verify_host: false✅ 此配置仅影响 Symfony 内部 HTTP 请求(包括 Mercure HubInterface::publish()),不会降低生产环境安全性——生产环境应使用真实 TLS 证书,并保持 verify_peer: true(默认值)。
? 补充说明与最佳实践
不要修改 php.ini 全局禁用 SSL 验证(如 openssl.cafile 置空或 verify_peer = Off),这会危及所有 PHP HTTP 请求的安全性。
-
若你使用自定义 HttpClient 实例(非默认),请确保其配置同步更新:
use Symfony\Component\HttpClient\HttpClient; $client = HttpClient::create(['verify_peer' => false]); // 再传入 Hub 构造器(如需自定义 Hub 实例)
-
对于 file_get_contents() 方式调用,可通过流上下文显式关闭验证:
$context = stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => "Authorization: Bearer {$jwt}\r\nContent-Type: application/x-www-form-urlencoded", 'content' => http_build_query(['topic' => $topic, 'data' => $data]), ], 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, ], ]); file_get_contents('https://localhost/.well-known/mercure', false, $context);
? 生产环境重要提醒
绝对禁止在生产环境设置 verify_peer: false!
生产部署 Mercure Hub 时,请务必:
- 使用 Let’s Encrypt 或其他可信 CA 签发的有效证书;
- 确保 Caddy 配置正确加载证书(如 tls internal 仅用于内网测试,不可用于公网);
- 保留 verify_peer: true(默认),以保障 JWT 发布请求的传输机密性与完整性。
通过以上配置,Symfony 应用即可在本地无缝对接 Caddy Mercure Hub,彻底解决 “Failed to send an update” 的 SSL 阻断问题,同时兼顾开发效率与生产安全边界。










