Heroku部署服务器与Netlify客户端的CORS请求阻止问题求助
在线石头剪刀布游戏CORS错误排查与解决
问题背景
开发了一款在线石头剪刀布游戏,服务器部署在Heroku平台,客户端部署在Netlify平台,浏览器控制台出现「request blocked by cors policy」错误,尝试多种解决方案后要么无效,要么引发其他错误。
服务器参考代码
const express = require("express"); const app = express(); const http = require("http"); const { Server } = require("socket.io"); const socketio = require("socket.io"); const cors = require("cors"); app.use(cors()); const server = http.createServer(app); const routes = require("./routes"); app.use("/", routes); let players = []; let otherPlayerChoice = null; let playerChoice = null; // const io = new Server(server, { // cors: { // origin: "https://64372cd23c90670060779932--onlinerock.netlify.app/", // methods: ["GET", "POST"], // }, // }); const io = socketio(server); // const cors = require("cors"); const corsOptions = { origin: "*", credentials: true, //access-control-allow-credentials:true optionSuccessStatus: 200, }; app.use(cors(corsOptions)); // Use this after the variable declaration io.on("connection", (socket) => { console.log(`User Connected: ${socket.id}`); players.push(socket.id); socket.on("join-room", (number) => { socket.join(number); }); const playerNumber = players.indexOf(socket.id); socket.emit("playerNumber", playerNumber); socket.on("disconnect", () => { console.log(`User Disconnected: ${socket.id}`); const index = players.indexOf(socket.id); players.splice(index, 1); }); socket.on("choice", (data) => { console.log(`Player ${data.playerNumber} chose ${data.choice}`); // Find the other player const otherPlayer = players.find((player) => player !== socket.id); // Get the other player's choice socket.to(otherPlayer).emit("opposing-player-move", data.choice); socket.on("test", (move) => { otherPlayerChoice = move.choice; playerChoice = data.choice; // Determine the winner let result; if (playerChoice === otherPlayerChoice) { result = "It's a tie!"; } else if ( (playerChoice === 0 && otherPlayerChoice === 2) || (playerChoice === 1 && otherPlayerChoice === 0) || (playerChoice === 2 && otherPlayerChoice === 1) ) { result = `Player ${data.playerNumber === 0 ? 1 : 0} wins!`; } else { result = `Player 2 wins!`; } // Emit the result to both players io.to(move.room).emit("game-result", result); // io.to(otherPlayer).emit("game-result", result); io.emit("disable-buttons"); }); }); }); server.listen(process.env.PORT || 5000, () => { console.log("SERVER IS RUNNING"); });
问题根源
- Socket.IO未配置CORS:你注释掉了带CORS配置的
Server初始化代码,改用未配置CORS的socketio(server)。Socket.IO的连接请求不受Express的cors中间件控制,必须单独配置CORS规则。 - Express的CORS中间件重复配置:先后调用
app.use(cors())和app.use(cors(corsOptions)),导致配置冲突,可能引发不可预期的CORS行为。
可行解决方案
1. 正确配置Socket.IO的CORS
替换当前的Socket.IO初始化代码,启用针对Netlify客户端的CORS配置:
// 替换原来的const io = socketio(server); const io = new Server(server, { cors: { origin: "https://64372cd23c90670060779932--onlinerock.netlify.app", methods: ["GET", "POST"], credentials: true }, });
2. 清理Express的CORS重复配置
删除重复的app.use(cors())调用,保留一套明确的CORS配置(如果Express路由需要CORS支持):
// 删除原来的app.use(cors()); const corsOptions = { origin: "https://64372cd23c90670060779932--onlinerock.netlify.app", credentials: true, optionSuccessStatus: 200, }; app.use(cors(corsOptions));
3. 验证客户端Socket连接地址
确保客户端连接Socket.IO时使用Heroku服务器的完整域名,示例:
// 客户端代码示例 const socket = io("https://your-heroku-app-domain.herokuapp.com");
额外优化建议
- 生产环境避免使用
origin: "*",严格指定允许的域名,提升安全性。 - 检查Heroku环境变量配置,确保服务器正常监听
process.env.PORT端口。 - 确认客户端与服务器的Socket.IO版本兼容,版本不匹配可能导致连接异常。
内容的提问来源于stack exchange,提问作者Stefan-Yves
相关产品推荐
相关产品推荐

