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

NodeJS+Socket.io WebSocket连接后立即断开问题求助

问题描述

后端基于NodeJS开发,前端采用NextJS,尝试建立WebSocket连接时,服务器刚完成连接就立即断开Socket。刷新前端页面后,服务器日志输出:

user connected ----  OKGG9r0qvvBs0EWeAAAB test@test.com  socket disconnected--- OKGG9r0qvvBs0EWeAAAB test@test.com

服务端代码

import express from "express";
import dotenv from "dotenv";
import http from "http";
import { Server, Socket } from "socket.io";
import userRoutes from "./routes/users";
import { DefaultEventsMap } from "socket.io/dist/typed-events";

dotenv.config();

const PORT = process.env.PORT || 5000;
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
  cors: {
    origin: process.env.CLIENT_URL,
  },
});

app.use(express.json());

app.get("/ping", (req, res) => res.status(200).send("Pong"));

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "http://localhost:3000");
  res.header("Access-Control-Allow-Credentials", "true");
  res.header("Access-Control-Allow-Methods", "POST, GET");
  res.header(
    "Access-Control-Allow-Headers",
    "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
  );
  next();
});

interface SType extends Socket {
  email?: string;
}

io.use((socket: SType, next) => {
  const userEmail = socket.handshake.auth.email;
  if (!userEmail) {
    return next(new Error("Invalid email"));
  }
  console.log("userEmail-----", userEmail);
  socket.email = userEmail;
  next();
});

io.on("connection", (socket) => {
  const users = [];
  for (let [id, socket] of io.of("/").sockets) {
    users.push({
      userID: id,
      email: (socket as any).email,
    });
    socket.emit("users", users);
  }

  socket.broadcast.emit("user connected", {
    userID: socket.id,
    email: (socket as any).email,
  });
  console.log("user connected ---- ", socket.id, (socket as any).email);

  socket.on("disconnect", () => {
    console.log("socket disconnected---", socket.id, (socket as any).email);
    (socket as any).email = "";
  });
});

app.use("/users", userRoutes);

server.listen(PORT, () => console.log(`server running on port ${PORT}`));

客户端代码

useEffect(() => {
  if (userState) {
    socket.auth = { email: userState.email };
  }
}, [userState]);
useEffect(() => {
  socket.on("users", (users: any) => {
    console.log("users", users);
    setUsers(users);
  });
  socket.on("user connected", (user: any) => {
    setUsers((previousState: any) => [...previousState, user]);
  });
}, [socket]);

已尝试Stack Overflow和Socket.io官方文档的方案,但均无效,求问题原因及解决办法。


问题排查与解决
  • CORS配置冲突:服务端同时配置了Socket.io的cors选项和Express的CORS中间件,规则冲突可能导致连接异常。建议移除Express的CORS中间件,仅保留Socket.io的配置,确保process.env.CLIENT_URL正确设置为http://localhost:3000(与前端地址一致)。

  • 客户端Socket auth传递时机错误:客户端在useEffect中事后赋值socket.auth,若此时Socket已发起连接,auth信息无法被正确传递。需在Socket实例创建时直接传入auth参数:

    const socket = io("http://localhost:5000", {
      auth: { email: userState?.email }
    });
    

    若userState为异步获取,需在userState就绪后创建Socket,或赋值后调用socket.connect()重新连接:

    useEffect(() => {
      if (userState) {
        socket.auth = { email: userState.email };
        socket.connect();
      }
    }, [userState]);
    
  • 服务端变量覆盖问题:connection事件处理中,遍历sockets时重复使用变量名socket,覆盖了当前连接的Socket对象,导致后续逻辑异常触发断开。修改循环变量名:

    for (let [id, clientSocket] of io.of("/").sockets) {
      users.push({
        userID: id,
        email: (clientSocket as any).email,
      });
      clientSocket.emit("users", users);
    }
    
  • NextJS Socket实例管理问题:若Socket实例全局创建,页面刷新或路由切换时易出现重复连接/断开。建议在组件内创建实例,并在组件卸载时主动断开:

    useEffect(() => {
      const socket = io("http://localhost:5000", {
        auth: { email: userState?.email }
      });
    
      socket.on("users", (users) => {
        setUsers(users);
      });
      socket.on("user connected", (user) => {
        setUsers(prev => [...prev, user]);
      });
    
      return () => {
        socket.disconnect();
      };
    }, [userState]);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 04:00:46