You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 02:45:50