如何修复多人贪吃蛇游戏开发中的Socket.io CORS错误
问题
开发多人贪吃蛇游戏时遇到CORS错误:
Access to XMLHttpRequest at 'http://localhost:5500/socket.io/?EIO=4&transport=polling&t=OAQWdpu' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:5500' that is not equal to the supplied origin.
使用VSCode的Live Server扩展在Edge浏览器中运行页面,跟着教程开发到15分钟左右卡住,尝试过Socket.io官方CORS配置但无效。相关代码如下:
server.js
const httpServer = require("http").createServer(); const io = require("socket.io")(httpServer, { cors: { origin: "http://localhost:5500", allowedHeaders: ["my-custom-header"], credentials: true } }); io.on('connection', client =>{ client.emit('init', { data: 'hello world' }); }); io.listen(5500);
index.js
const BG_COLOUR = '#231f20'; const SNAKE_COLOUR = '#c2c2c2'; const FOOD_COLOUR = '#e66916'; // client-side const socket = io('http://localhost:5500', { withCredentials: true, extraHeaders: { "my-custom-header": "abcd" } }); socket.on('init', handleInit); const gameScreen = document.getElementById('gameScreen'); let canvas, ctx; const gameState = { player: { pos: { x: 3, y: 10, }, vel: { x: 1, y: 0, }, snake: [ {x: 1, y: 10}, {x: 2, y: 10}, {x: 3, y: 10}, ], }, food: { x: 7, y: 7, }, gridsize: 20, }; function init(){ canvas = document.getElementById('canvas'); ctx = canvas.getContext('2d'); canvas.width = canvas.height = 600; ctx.fillStyle = BG_COLOUR; ctx.fillRect(0, 0, canvas.width, canvas.height); document.addEventListener('keydown', keydown); } function keydown(e){ console.log(e.KeyCode); } init(); function paintGame(state){ ctx.fillStyle = BG_COLOUR; ctx.fillRect(0, 0, canvas.width, canvas.height); const food = state.food; const gridsize = state.gridsize; const size = canvas.width / gridsize; ctx.fillStyle = FOOD_COLOUR; ctx.fillRect(food.x * size, food.y * size, size, size); paintPlayer(state.player, size, SNAKE_COLOUR); } function paintPlayer(playerState, size, colour){ const snake = playerState.snake; ctx.fillStyle = colour; for(let cell of snake){ ctx.fillRect(cell.x * size, cell.y * size, size , size); } } paintGame(gameState); function handleInit(msg){ console.log(msg); }
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MultiPlayer Snake</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> </head> <body> <section class="vh-100"> <div class="container h-100"> <div id="gameScreen" class="h-100"> <div class="d-flex flex-column align-items-center justify-content-center h-100"> <!-- <h1>Your game code is: <span id="gameCodeDisplay"></span></h1> --> <canvas id="canvas"></canvas> </div> </div> </div> </section> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.1/socket.io.js"></script> <script type="module" src="index.js"></script> </body> </html>
解决方案
错误核心是CORS的Origin严格匹配:服务器配置允许的Origin是http://localhost:5500,但Live Server实际运行页面的地址是http://127.0.0.1:5500,这两个地址在CORS规则里被视为不同源,导致验证失败。
有两种简单修复方式:
方式一:修改服务器CORS配置,允许两个源
将origin设置为包含两个地址的数组,覆盖两种访问场景:
const io = require("socket.io")(httpServer, { cors: { origin: ["http://localhost:5500", "http://127.0.0.1:5500"], allowedHeaders: ["my-custom-header"], credentials: true } });
方式二:强制Live Server使用localhost
修改VSCode的Live Server配置:
- 打开VSCode设置(快捷键
Ctrl+,) - 搜索
Live Server: Host - 将值改为
localhost - 重启Live Server,页面将以
http://localhost:5500打开,与服务器配置的Origin完全匹配
额外优化:简化不必要配置
如果不需要自定义头部和凭证,可简化配置减少干扰:
服务器端:
const io = require("socket.io")(httpServer, { cors: { origin: ["http://localhost:5500", "http://127.0.0.1:5500"] } });
客户端:
const socket = io('http://localhost:5500');
内容的提问来源于stack exchange,提问作者amazegames

