Docker环境Symfony调用Mercure发布消息报3000端口连接拒绝
问题现象
- 场景:Symfony 控制器中调用 Mercure Hub 发布消息时报错,Postman、Mercure 自带演示页面(
http://localhost:3000/.well-known/mercure/ui/)操作均正常,前端订阅 Mercure 事件也正常 - 报错信息:执行
$hub->publish($update);时抛出TransportException,提示Failed to connect to localhost port 3000 after 0 ms: Connection refused for "http://localhost:3000/.well-known/mercure"
现有配置
docker-compose.yaml 中 Mercure 服务配置
mercure: image: dunglas/mercure restart: unless-stopped environment: SERVER_NAME: ':80' DEMO: 1 PUBLISH_ALLOWED_ORIGINS: '*' MERCURE_CORS_ALLOWED_ORIGINS: '*' ALLOW_ANONYMOUS: 1 MERCURE_EXTRA_DIRECTIVES: |- cors_origins "http://localhost:8000" anonymous MERCURE_PUBLISHER_JWT_KEY: '!ChangeMe!' MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeMe!' # 注释以下行即可关闭开发模式 command: /usr/bin/caddy run -config /etc/caddy/Caddyfile.dev
.env 中 Mercure 相关配置
MERCURE_URL=http://localhost:3000/.well-known/mercure # Mercure Hub的公开访问地址,供浏览器端连接使用 MERCURE_PUBLIC_URL=http://localhost:3000/.well-known/mercure MERCURE_PUBLISH_URL=http://mercure:3000/.well-known/mercure # 用于签名JWT的密钥 MERCURE_JWT_SECRET=!ChangeMe!
前端正常订阅代码
<script> const eventSource = new EventSource("{{ mercure('topic')|escape('js') }}"); eventSource.onmessage = event => { // 服务端每次发布更新时都会触发该回调 console.log(JSON.parse(event.data)); } </script>
排查解决步骤
核心问题定位:容器网络访问逻辑错误
如果 Symfony 应用运行在 Docker 容器内,容器内部的localhost指向的是 Symfony 容器自身,不是宿主机,也不是 Mercure 容器。另外配置中 Mercure 容器内部服务监听的是80端口(对应SERVER_NAME: ':80'配置),3000是映射到宿主机的端口,容器内部访问不需要走宿主机端口映射。修正.env配置项
打开 Symfony 的.env文件,调整服务端访问 Mercure 的地址为容器内可访问的地址:# 服务端(Symfony容器内)通过Docker服务名访问Mercure,走容器内监听的80端口 MERCURE_URL=http://mercure/.well-known/mercure # 浏览器端访问保持宿主机映射地址不变 MERCURE_PUBLIC_URL=http://localhost:3000/.well-known/mercure MERCURE_PUBLISH_URL=http://mercure/.well-known/mercure MERCURE_JWT_SECRET=!ChangeMe!注意:原配置中
MERCURE_PUBLISH_URL写的http://mercure:3000是错误的,3000是宿主机映射端口,容器内无3000端口监听。补全校验docker-compose端口映射
贴出的配置中漏了Mercure的端口映射段,需要确认mercure服务下配置了端口映射,否则宿主机3000端口无法访问,补全后参考配置如下:mercure: image: dunglas/mercure restart: unless-stopped ports: - "3000:80" # 宿主机3000端口映射到容器内80端口,前端、Postman访问靠这个规则生效 environment: # 原有环境变量保持不变 SERVER_NAME: ':80' DEMO: 1 PUBLISH_ALLOWED_ORIGINS: '*' MERCURE_CORS_ALLOWED_ORIGINS: '*' ALLOW_ANONYMOUS: 1 MERCURE_EXTRA_DIRECTIVES: |- cors_origins "http://localhost:8000" anonymous MERCURE_PUBLISHER_JWT_KEY: '!ChangeMe!' MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeMe!' command: /usr/bin/caddy run -config /etc/caddy/Caddyfile.dev清理缓存重启服务
执行以下命令清理Symfony缓存,重启容器让配置生效:# 清理Symfony配置缓存 php bin/console cache:clear # 重启相关容器,php替换为你本地Symfony服务的容器名 docker compose restart php mercure连通性校验
进入Symfony所在的PHP容器内部,执行curl命令测试连通性:# 进入PHP容器 docker compose exec php bash # 容器内测试访问Mercure curl http://mercure/.well-known/mercure如果返回
Missing "topic" parameter提示,说明容器内网络连通正常,再调用发布接口就不会出现连接拒绝错误。
内容的提问来源于stack exchange,提问作者Den Step
相关产品推荐
相关产品推荐

