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

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");
});

问题根源

  1. Socket.IO未配置CORS:你注释掉了带CORS配置的Server初始化代码,改用未配置CORS的socketio(server)。Socket.IO的连接请求不受Express的cors中间件控制,必须单独配置CORS规则。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:58:09