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

Socket.io跨域连接失败:CORS策略拦截请求,缺少Access-Control-Allow-Origin头

Socket.io跨域连接失败问题排查与解决

问题情况

服务端运行在3000端口,客户端通过Live Server在5001端口运行,尝试建立Socket.io连接时持续触发CORS错误,每秒重复出现:

Access to XMLHttpRequest at 'http://localhost:3000/socket.io/?EIO=4&transport=polling&t=Oz_5Qur' from origin 'http://127.0.0.1:5001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

需求:新连接建立时终端打印“user connected”,断开时打印“user disconnected”。

相关代码

服务端 index.js

import express from 'express';
import { createServer } from 'node:http';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { Server } from 'socket.io';
import cors from 'cors';

const app = express();
const server = createServer(app);
const io = new Server(server);
const __dirname = dirname(fileURLToPath(import.meta.url));

app.use(cors()); 
app.use('/socket.io', express.static(join(__dirname, 'node_modules', 'socket.io', 'client-dist')));
app.use(express.static(join(__dirname, 'myapp')));
console.log(__dirname);

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5001/");
  res.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE");
  res.setHeader("Access-Control-Allow-Headers", "Origin, Accept, Content-Type, Authorization");
  next();
})
app.get('/', (req, res) => {
  res.sendFile(join(__dirname, 'server.html'));
});

io.on('connection', (socket) => {
  console.log('a user connected');

  socket.on('disconnect', () => {
    console.log('user disconnected');
  });
});

server.listen(3000, () => {
  console.log('server running at http://localhost:3000');
});

客户端 client.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <script src="http://localhost:3000/socket.io/socket.io.js"></script>
    <script>
        var socket = io('http://localhost:3000');
    </script>
</body>
</html>

服务端页面 server.html(无问题)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      var socket = io();
    </script>
</body>
</html>

问题根源与解决方法

核心问题是Socket.io的连接请求未被正确配置CORS:Express的cors()中间件和自定义header设置无法作用于Socket.io的连接流程,Socket.io有独立的CORS配置项,必须在初始化Server时单独设置。

修改步骤:

  1. 移除冗余配置:删掉app.use(cors())和自定义的header中间件,避免规则冲突。
  2. 配置Socket.io的CORS规则:修改io的初始化代码,指定允许的源和方法:
// 替换原有的const io = new Server(server);
const io = new Server(server, {
  cors: {
    origin: "http://127.0.0.1:5001", // 注意不要加末尾斜杠
    methods: ["GET", "POST"]
  }
});
  1. 可选:统一连接地址:客户端的io('http://localhost:3000')可正常使用,也可改为io('http://127.0.0.1:3000'),和服务端监听地址保持一致,避免域名解析潜在问题。

原理说明

Express的CORS中间件仅处理常规HTTP请求,而Socket.io的连接初期虽发送HTTP轮询请求,但后续会由Socket.io自身接管,因此必须在Socket.io的初始化配置中单独设置CORS规则,才能覆盖整个连接流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:53:12