本地Nginx+npm run dev下WebSocket正常,Docker Compose部署后连接失败
问题描述
我使用React前端、Node.js后端,通过Nginx实现服务部署与负载均衡。本地运行Nginx并执行npm run dev时整个架构运行正常,但通过Docker Compose部署为容器后,WebSocket无法建立连接。
控制台报错
websocket.js:43 WebSocket connection to 'ws://localhost/socket.io/?userId=6500d7f273ec607346da303c&EIO=4&transport=websocket' failed:
配置信息
docker-compose.yml
services: ws1: image: bark-mate-be environment: - APPID=1111 - APPPORT=8081 networks: - loadbalancing ports: - "8081:8080" ws2: image: bark-mate-be environment: - APPID=2222 - APPPORT=8082 ports: - "8082:8080" networks: - loadbalancing ws3: image: bark-mate-be environment: - APPID=3333 - APPPORT=8083 ports: - "8083:8080" networks: - loadbalancing barkmatefrontend: image: bark-mate-fe ports: - "3000:80" networks: - loadbalancing depends_on: - db - ws1 - ws2 - ws3 db: volumes: - barkMate_db:/data/db image: mongo:latest ports: - "27017:27017" volumes: barkMate_db: networks: loadbalancing:
nginx.conf
map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream loadbalancer { # ip_hash; hash $remote_addr consistent; server ws1:8081; server ws2:8082; } server { listen 80; listen [::]:80; server_name localhost; location /socket.io/ { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://loadbalancer; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /api/ { proxy_pass http://loadbalancer; proxy_buffering on; } location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; } }
socketio.js
import { io } from "socket.io-client"; const user = JSON.parse(localStorage.getItem("user")); export let socket = io("http://localhost:80", { path: "/socket.io/", auth: { token: "token" }, query: { userId: user ? JSON.parse(localStorage.getItem("user"))._id : "" }, autoConnect: false, transports: ["websocket"], withCredentials: true, }); socket.onAnyOutgoing((e, m) => { console.log("any out going", e, m); }); socket.on("connect", () => { console.log("socket has connected"); socket.emit("message", { type: "test", content: { msg: "test message", userId: JSON.parse(localStorage.getItem("user"))._id, }, }); }); socket.on("message", (msg) => { console.log("client recieved the message", msg); }); socket.io.on("reconnect", (attempt) => { console.log("socket reconnection success"); });
Dockerfile(前端)
FROM node:current-alpine as build WORKDIR /app COPY package*.json /app/ RUN npm install RUN npm ci --production COPY . . RUN npm run build FROM nginx:stable COPY --from=build /app/build/ /usr/share/nginx/html COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
解决方案
核心问题分析
- Nginx未纳入容器网络:当前Docker Compose未包含Nginx服务,前端容器的Nginx仅负责静态文件,WebSocket与API转发逻辑未在容器环境生效;本地单独运行Nginx时能正常转发,但容器环境下前端代码请求
localhost:80无对应服务监听。 - 后端端口映射混淆:Nginx配置的upstream指向后端容器的外部映射端口(8081/8082),但容器内部服务实际运行在8080端口,导致转发失败。
- WebSocket连接地址硬编码:前端代码固定连接
http://localhost:80,容器部署后用户访问前端3000端口时,WebSocket请求会直接打向本地80端口,而非正确的Nginx转发入口。
具体修复步骤
1. 调整Docker Compose,加入Nginx服务
将Nginx作为单独容器纳入网络,统一处理静态文件、API与WebSocket转发:
services: ws1: image: bark-mate-be environment: - APPID=1111 networks: - loadbalancing ws2: image: bark-mate-be environment: - APPID=2222 networks: - loadbalancing ws3: image: bark-mate-be environment: - APPID=3333 networks: - loadbalancing barkmatefrontend: image: bark-mate-fe networks: - loadbalancing depends_on: - db - ws1 - ws2 - ws3 db: volumes: - barkMate_db:/data/db image: mongo:latest networks: - loadbalancing nginx: image: nginx:stable ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf networks: - loadbalancing depends_on: - barkmatefrontend - ws1 - ws2 - ws3 volumes: barkMate_db: networks: loadbalancing:
2. 修正Nginx配置
- 调整upstream指向后端容器内部端口(8080),并补充ws3节点
- 修改静态文件转发指向前端容器:
upstream loadbalancer { hash $remote_addr consistent; server ws1:8080; server ws2:8080; server ws3:8080; } server { listen 80; listen [::]:80; server_name localhost; location /socket.io/ { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://loadbalancer; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /api/ { proxy_pass http://loadbalancer; proxy_buffering on; } location / { proxy_pass http://barkmatefrontend; try_files $uri $uri/ /index.html; } }
3. 修正前端Socket连接地址
使用相对路径替代硬编码地址,自动适配当前访问域名:
import { io } from "socket.io-client"; const user = JSON.parse(localStorage.getItem("user")); export let socket = io("", { path: "/socket.io/", auth: { token: "token" }, query: { userId: user ? user._id : "" }, autoConnect: false, transports: ["websocket"], withCredentials: true, });
验证步骤
- 重新构建前端与后端镜像(若代码有修改)
- 执行
docker-compose up -d启动所有服务 - 访问
http://localhost,检查WebSocket连接状态
内容的提问来源于stack exchange,提问作者Anthony T
相关产品推荐
相关产品推荐

