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

Docker Compose环境下Socket.io服务无法连接求助

Docker容器中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.io Server类型,包含自定义事件映射

前端连接代码

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基础连接是否正常,再逐步恢复验证。


验证步骤

  1. 修改后端代码后,重启服务:docker-compose down && docker-compose up --build
  2. 查看后端日志,确认服务监听地址为0.0.0.0:6666
  3. 用curl测试后端接口:curl "http://localhost:6666/socket.io/?EIO=4&transport=polling",检查是否有正常响应
  4. 重新访问前端页面,测试Socket.io连接

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:54:55