根本原因是node.js容器内localhost指向自身而非php容器,应改用docker-compose中定义的服务名(如http://php-app:80)通信,并确保php监听*:80而非127.0.0.1:80。

Node.js 容器里 fetch 或 axios 请求 PHP 容器返回 ECONNREFUSED
根本原因不是端口没映射,而是 Node.js 代码里写了 http://localhost:8080 —— 在容器内,localhost 指的是它自己,不是宿主机,更不是同网桥下的另一个容器。
正确做法是用 Docker 自定义网络中的服务名(即 docker-compose.yml 里定义的 service 名)作为 host:
- PHP 服务在
docker-compose.yml中叫php-app,Node.js 就该请求http://php-app:80 - 确保两个服务在同一个自定义网络(不要依赖默认
bridge),例如声明networks: [app-network] - Node.js 容器里不需要暴露端口(
ports:是给宿主机访问用的),PHP 容器也只需expose: [80],不用ports:
Docker Compose 里 PHP 的 ports 和 expose 混用导致连通性混乱
ports 是把容器端口绑定到宿主机,用于外部访问;expose 只是声明该端口“对同一网络内其他容器可见”,不绑定宿主机,更安全。
常见错误写法:
立即学习“PHP免费学习笔记(深入)”;
php-app: image: php:8.2-apache ports: ["8080:80"] # ← 这会让宿主机能访问,但和 Node.js 容器通信无关,还可能被防火墙或端口占用干扰
推荐写法:
php-app: image: php:8.2-apache expose: ["80"] networks: ["app-network"] <p>node-app: image: node:18 depends_on: [php-app] networks: ["app-network"]
这样 Node.js 容器内 curl -v http://php-app 就能通,且不暴露 PHP 到宿主机。
Node.js 用 http://host.docker.internal 临时调试失败
这个 DNS 名只在 Docker Desktop(macOS/Windows)上默认可用,Linux 上默认不启用,强行开启需加 --add-host=host.docker.internal:host-gateway 启动参数,不推荐用于生产或跨平台部署。
真正可移植的方案只有两种:
- 用
docker-compose的 service 名(如php-app),依赖 Docker 内置 DNS - 手动在
docker run时加--network-alias,但不如 compose 清晰
如果硬要用 host.docker.internal,检查是否漏了 extra_hosts 配置:
node-app:
extra_hosts:
- "host.docker.internal:host-gateway"PHP 容器 Apache 监听地址没改导致只响应 localhost
默认 Apache 可能只监听 127.0.0.1:80,这在容器内会导致它拒绝来自其他容器(比如 Node.js)的连接,因为对方 IP 不是 127.0.0.1。
检查并修改 Apache 配置(如 /etc/apache2/sites-enabled/000-default.conf):
- 确认
Listen 80没写成Listen 127.0.0.1:80 - 确认
<virtualhost></virtualhost>,不是<virtualhost></virtualhost> - 重启 Apache:
apache2-ctl restart或重载配置
一个快速验证方式:进 Node.js 容器执行 telnet php-app 80,如果连不上,大概率是 PHP 服务没监听所有接口。
Docker 网络连通的核心就两点:容器间用 service 名通信、PHP 服务必须监听 *:80 而非 127.0.0.1:80。其余所有端口映射、host 设置、DNS 配置,都是围绕这两点打补丁。











