You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Docker部署聊天应用:前端JS连接NodeJS与Apache容器异常问题

解决Docker环境下前端无法通过容器名连接Socket.io Node.js服务的问题

嘿,我前阵子刚踩过这个坑,立刻给你说清楚问题出在哪以及怎么解决!

问题根源

你提到用容器名nodejs作为连接地址,这个逻辑在Docker容器之间的内部网络是成立的,但浏览器是运行在用户的本地机器上,它不在Docker的内部网络里,根本识别不了nodejs这个主机名——这就是为什么浏览器会报GET http://nodejs:3000/socket.io/socket.io.js找不到的错误。

两种可行解决方案

方案1:端口映射+主机地址访问(适合开发环境)

第一步,先在你的docker-compose.yml里给Node.js容器添加端口映射,把容器的3000端口暴露到宿主机:

services:
  nodejs:
    # 其他配置...
    ports:
      - "3000:3000" # 宿主机端口:容器端口
  apache:
    # 其他配置...
    ports:
      - "80:80"

第二步,前端代码里不要用容器名,改用宿主机的地址(开发环境用localhost,部署到服务器就用服务器的IP/域名):

// 引入socket.io客户端脚本
<script src="http://localhost:3000/socket.io/socket.io.js"></script>
// 或者用动态地址适配不同环境
<script src="http://${window.location.hostname}:3000/socket.io/socket.io.js"></script>

// 建立连接
const socket = io('http://localhost:3000');
// 同样可以用动态地址
const socket = io(`http://${window.location.hostname}:3000`);

这样浏览器就能通过宿主机的端口访问到Node.js容器里的Socket.io服务了。

方案2:Apache反向代理(推荐生产环境)

如果是生产环境,直接暴露Node.js的端口不太安全,而且前端代码带端口也不优雅,这时候可以用Apache做反向代理,把前端对/socket.io路径的请求转发到Node.js容器。

第一步,确保你的Apache容器和Node.js容器在同一个Docker网络里(默认Compose会创建一个共享网络,所以只要是同一个docker-compose.yml里的服务就没问题)。

第二步,在Apache的配置文件里添加反向代理规则:

# 开启必要的模块(如果没开的话)
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so # 处理WebSocket连接

# 反向代理配置
ProxyPass /socket.io http://nodejs:3000/socket.io
ProxyPassReverse /socket.io http://nodejs:3000/socket.io
# WebSocket支持
ProxyPass /socket.io/ ws://nodejs:3000/socket.io/
ProxyPassReverse /socket.io/ ws://nodejs:3000/socket.io/

第三步,前端代码就可以简化成这样,不用指定端口和主机名,直接用当前页面的域名:

<script src="/socket.io/socket.io.js"></script>
const socket = io(); // 默认连接当前页面的域名和端口

这个方案的好处是:不用暴露Node.js的端口到外部网络,更安全;前端代码不用适配不同环境的地址,更简洁。

最后验证

不管用哪种方案,都要先确认:

  • Docker Compose里的服务都正常启动
  • 方案1里的端口映射没有被其他程序占用
  • 方案2里的Apache反向代理模块已经开启,配置正确

内容的提问来源于stack exchange,提问作者Niverhawk

火山引擎 最新活动