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

Render部署环境下Socket.io连接失败问题求助

Socket.io部署Render后跨域连接失败问题

问题描述

按照Socket.io官方文档在Node.js服务器上搭建服务后,本地客户端连接服务端时,服务端日志正常输出connected;Postman也能成功建立连接。但当客户端(React应用)与服务端均部署在Render平台后,客户端无法建立Socket.io连接,服务端无connected日志输出。

测试场景结果:

  • 本地客户端+本地服务端:Socket.io连接成功
  • 本地客户端+Render托管服务端:Socket.io连接成功
  • Render托管客户端+Render托管服务端:Socket.io连接失败

环境配置

  • 服务端与客户端均托管于Render.com
  • Node.js服务基于Express框架搭建,包含可正常运行的REST API与Socket.io
  • 客户端采用React框架开发

服务端代码

const supabase = require("./configdb.js");
const express = require("express");

const app = express();
const cors = require("cors");
const port = 3000;

app.use(cors());

app.use(express.json());

//socket.io
const httpServer = require("http").createServer(app);
const options = {
  cors: {
    origin: ["http://localhost:3000", "https://project001-ejm9.onrender.com/"],// 开发和生产环境路径
    methods: ["GET", "POST"],
  },
};
const io = require("socket.io")(httpServer, options);

// 记录在线用户
let onlineUsers = {};

io.on("connection", (socket) => {
  console.log("connected");
  socket.on("userEntered", (user) => {
    onlineUsers[socket.id] = user;
    io.emit("updateUserList", Object.values(onlineUsers));
    console.log(Object.values(onlineUsers));
    console.log(user);
  });

  socket.on("connect_error", (err) => {
    console.log(`connect_error due to ${err.message}`);
  });

  socket.on("disconnect", () => {
    delete onlineUsers[socket.id];
    io.emit("updateUserList", Object.values(onlineUsers));
    console.log("disconnect");
  });
});

// 启动服务监听端口
httpServer.listen(port, () => {
  console.log(`Server is running on port ${port}.`);
});

// 注册路由
require("./routes/chat.routes.js")(express, app);

客户端代码

import { io } from "socket.io-client";
import { useEffect, useState } from "react";

const socket = io("https://project001db-11.onrender.com/");

export const useSocket = () => {
  useEffect(() => {
    return () => {
      socket.disconnect();
    };
  }, []);

  return useSocket;
};

export const useRegisterOnlineUser = (username) => {
  const [onlineUsers, setOnlineUsers] = useState([]);

  useEffect(() => {
    if (!username) return;

    const user = { username: username };
    socket.emit("userEntered", user, () => {
      console.log("emitted event-userConnected");
    });

    socket.on("updateUserList", (users) => {
      setOnlineUsers(users);
      console.log("updateUserList event received", users);
    });

    // 组件卸载时清理监听
    return () => {
      socket.off("updateUserList");
    };
  }, [username]);

  return onlineUsers;
};

已尝试的解决方法

  • 排查SSL问题:通过SSL测试确认服务端HTTPS配置正常,获得A级评分
  • Postman测试:可成功建立Socket.io连接

调试错误信息

添加客户端错误监听代码:

socket.on("connect_error", (err) => {
    console.error("Connection error:", err);
});

得到以下错误:

Access to XMLHttpRequest at 'https://project001db-11.onrender.com/socket.io/?EIO=4&transport=polling&t=P1VQHOx' from origin 'https://project001-ejm9.onrender.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

polling.js:298
GET https://project001db-11.onrender.com/socket.io/?EIO=4&transport=polling&t=P1VQHOx net::ERR_FAILED 200 (OK)

socketio.js:34 Connection error: Error: xhr poll error
at polling.onError (transport.js:38:37)
at yd. (polling.js:218:18)
at Yu.emit (index.js:136:20)
at yd.onError (polling.js:320:14)
at polling.js:294:30


解决方案

1. 修正CORS配置的域名格式

服务端Socket.io的CORS配置中,生产环境域名末尾多了斜杠,浏览器请求的Origin头不带末尾斜杠,导致匹配失败。去掉斜杠即可:

const options = {
  cors: {
    origin: ["http://localhost:3000", "https://project001-ejm9.onrender.com"],// 移除末尾斜杠
    methods: ["GET", "POST"],
    credentials: true // 若需要传递Cookie等凭证,开启此项
  },
};

2. 统一Express与Socket.io的CORS配置

Express的cors()中间件和Socket.io的CORS配置需保持一致,避免冲突:

const allowedOrigins = ["http://localhost:3000", "https://project001-ejm9.onrender.com"];
// Express CORS配置
app.use(cors({
  origin: allowedOrigins,
  credentials: true
}));

// Socket.io复用同一域名列表
const options = {
  cors: {
    origin: allowedOrigins,
    methods: ["GET", "POST"],
    credentials: true
  },
};

3. 适配Render的端口环境变量

Render会自动分配端口,不要硬写固定端口,改用环境变量:

const port = process.env.PORT || 3000;

4. 优化客户端Socket连接配置

客户端连接时指定传输方式并开启凭证支持:

const socket = io("https://project001db-11.onrender.com", {
  withCredentials: true,
  transports: ["websocket", "polling"] // 优先使用WebSocket,降级到polling
});

5. 检查Render网络配置

确认服务端与客户端处于同一区域,无额外防火墙或安全组规则阻止Socket连接。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:39:51