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时单独设置。
修改步骤:
- 移除冗余配置:删掉
app.use(cors())和自定义的header中间件,避免规则冲突。 - 配置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"] } });
- 可选:统一连接地址:客户端的
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
相关产品推荐
相关产品推荐

