Docker Compose环境下Socket.io服务无法连接求助
问题概述
使用Vite/React构建前端、Socket.io构建后端服务,二者部署在独立Docker容器中,通过docker-compose管理。前端无法连接Socket.io服务,报错:
Firefox can’t establish a connection to the server at ws://localhost:6666/socket.io/?EIO=4&transport=websocket.
已确认端口配置正确,前后端容器处于同一Docker网络,尝试过将连接地址中的localhost替换为0.0.0.0、backend,也尝试去掉http://前缀,均无法解决问题。
关键配置信息
docker-compose.yml
version: '3.3' services: backend: build: ./backend working_dir: /app environment: PORT: ${BACK_PORT} JWT_SECRET: ${JWT_SECRET} ports: - ${BACK_PORT}:${BACK_PORT} volumes: - ./backend:/app - ./shared_types:/app/src/shared_types networks: - all restart: unless-stopped command: sh start.sh frontend: depends_on: - backend image: node:lts-alpine working_dir: /app environment: PORT: ${FRONT_PORT} VITE_BACK_PORT: ${BACK_PORT} ports: - ${FRONT_PORT}:${FRONT_PORT} volumes: - ./frontend:/app - ./shared_types:/app/src/shared_types networks: - all restart: unless-stopped command: sh start.sh networks: all: driver: bridge
后端Dockerfile
FROM node:lts-alpine RUN npm i -g npm@latest CMD ["npm", "run", "dev"]
.env 文件
BACK_PORT=6666 FRONT_PORT=8080 JWT_SECRET=ilovecandies
Socket.io后端服务代码
import type { ServerOptions, Socket } from './types/server'; import { Server } from 'socket.io'; import http from 'http'; import { SignJWT, jwtVerify } from 'jose'; import express from 'express'; const createServerOptions = (options?: Partial<ServerOptions>): ServerOptions => { return { port: 3000, ...options, }; }; export const createServer = (options?: Partial<ServerOptions>) => { const serverOptions = createServerOptions(options); const app = express(); const httpServer = http.createServer(app); const server: Socket = new Server(httpServer, { cors: { origin: '*', }, transports: ['websocket'], }); const secret = new TextEncoder().encode(process.env.JWT_SECRET!); server.on('connection', async socket => { console.log(`Client ${socket.id} connected!`); const verify = await jwtVerify(socket.handshake.auth.token, secret); console.log(verify); socket.on('disconnect', () => { console.log(`Client ${socket.id} disconnected!`); }); }); return { start: () => { console.log(`Server: listening on port ${serverOptions.port}.`); server.listen(serverOptions.port); } }; };
main.ts 代码
import { createServer } from './server'; (() => { const server = createServer({ port: +process.env.PORT!, }); server.start(); })();
注:
Socket类型是自定义的Socket.ioServer类型,包含自定义事件映射
前端连接代码
const socket = io(`http://localhost:${import.meta.env.VITE_BACK_PORT!}`, { transports: ["websocket"], reconnection: false, auth: { token: document.cookie .split("; ") .find(x => x.startsWith("snet-token=")) ?.split("=")[1] ?? "", }, });
问题排查与解决方案
1. 后端服务启动方式错误
当前代码中,你创建了httpServer但直接调用server.listen()启动Socket.io实例,正确做法应该是启动挂载了Socket.io的httpServer,否则Socket.io无法正确绑定到预期网络接口:
修改后端createServer的start方法:
return { start: () => { console.log(`Server: listening on port ${serverOptions.port}.`); httpServer.listen(serverOptions.port, '0.0.0.0', () => { console.log(`Server is running on 0.0.0.0:${serverOptions.port}`); }); } };
2. 后端监听地址限制
Docker容器内的Node.js服务默认只监听localhost(127.0.0.1),外部无法访问。必须指定监听0.0.0.0,这样才能接收来自容器外部/其他容器的连接,上述代码已包含此修改。
3. 前端连接地址逻辑修正
前端代码运行在浏览器中(宿主机环境),无法解析Docker内部的服务名backend。如果是在宿主机浏览器访问前端(如http://localhost:8080),前端连接地址应保持http://localhost:6666,确保后端容器的端口映射(6666:6666)正常生效。
4. JWT验证异常捕获
后端connection事件中直接执行await jwtVerify,若token为空或无效会抛出错误导致连接中断且无日志提示,需添加异常捕获:
server.on('connection', async socket => { console.log(`Client ${socket.id} connected!`); try { const verify = await jwtVerify(socket.handshake.auth.token, secret); console.log(verify); } catch (err) { console.error('JWT验证失败:', err); socket.disconnect(); return; } socket.on('disconnect', () => { console.log(`Client ${socket.id} disconnected!`); }); });
可先注释JWT验证逻辑,优先测试Socket.io基础连接是否正常,再逐步恢复验证。
验证步骤
- 修改后端代码后,重启服务:
docker-compose down && docker-compose up --build - 查看后端日志,确认服务监听地址为
0.0.0.0:6666 - 用curl测试后端接口:
curl "http://localhost:6666/socket.io/?EIO=4&transport=polling",检查是否有正常响应 - 重新访问前端页面,测试Socket.io连接
内容的提问来源于stack exchange,提问作者Fayeure

