socket.io 的节点服务器无法建立连接

Node server with socket.io wont establish connection

我最近刚开始学习如何使用 Node js 和 socket.io 制作多人 snake.io 游戏的在线教程。

https://www.youtube.com/watch?v=ppcBIHv_ZPs

客户端的设置非常顺利,但是一旦我尝试建立套接字(视频中为 15:20),客户端浏览器 chrome 控制台出现错误,尝试建立通信。起初我收到如下错误

127.0.0.1/:1 访问 XMLHttpRequest at 来自来源 'http://127.0.0.1:8080' 的 'http://localhost:3000/socket.io/?EIO=3&transport=polling&t=NfTLuxq' 已被 CORS 策略阻止:请求的资源上不存在 'Access-Control-Allow-Origin' header。

然后我对 CORS 是什么做了一些研究,据我所知,它就像一个安全协议,它限制不同 URL 之间的连接,这个错误需要 header 来保证安全原因?

我看到一位用户说他做到了,所以 socket.io 库在客户端和服务器端都是一样的。所以我从我的服务器端删除了 socket.io 文件,并使用我通过 cdn 拉入客户端的相同版本重新安装它们。我使用了命令 'yarn add socket.io@2.3.0'。我认为这可以解决问题,但是我收到了一个不同的错误,

"加载资源失败: net::ERR_CONNECTION_REFUSED

我也不明白为什么在这个项目中我们要从 index.html 中的 cdn 中拉入 socket.io(我不确定它是如何工作的),然后使用纱线来在服务器端添加 socket.io,然后我们必须使用 'require' 在 中再次 导入它。我不确定我是否理解这两种导入方法之间的区别 socket.io 以及为什么我们使用两种不同的方法。

如能帮助我消除关于为什么会收到这些错误和上一个问题的一些困惑,我们将不胜感激!

index.html

代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>>MultiPlayer Snake</title>
    <!-- Import bootstrap-css   --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
        integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
</head>

<body>
    <!-- Create a section that is 100% height of window.   -->
    <div class="container h-100">
    <section class="vh-100"> 

             
            <div id="gameScreen" class="h-100">
                <!-- Center canvas both horizontally and vertically using a few bootstrap classes -->
                <div class="d-flex flex-column align-items-center justify-content-center h-100">
                    <canvas id="canvas"></canvas>
                </div>
            </div>

        </div>
    </section>

    <!-- Pulling in socket.io from a cdn?   -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
    <!-- Importing index.js   -->
    <script src="index.js"></script>

</body>

</html>

index.js

代码
const BG_COLOUR = '#231f20';
const SNAKE_COLOUR = '#c2c2c2';
const FOOD_COLOUR = '#e66916';

const socket = io('http://localhost:3000');

socket.on('init', handleInit);

// Get a hold of the game screen div from html 
const gameScreen = document.getElementById('gameScreen');

// Create canvas and context elements, context->state
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,
};

// Initialize everything
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);
}


server.js

代码
// Import socket.io
const io = require('socket.io')();

// add listener
io.on('connection', client => {
 // Callback function
    // Raise an event.
    client.emit('init', {data: 'hello world' });
});


io.listen(3000);

我的文件结构。 My file sctructure

收到这个问题的反馈后,我添加了处理 cos 的代码,但这次我再次收到一条错误消息

从来源 'http://127.0.0.1:8080' 到 'http://localhost:3000/socket.io/?EIO=3&transport=polling&t=NfUVBF5' 处的 XMLHttpRequest 的访问已被 CORS 策略阻止:'Access-Control-Allow-Origin' header 具有值 'http://localhost:8080' 不等于提供的原点。

我在server.js

中写了这段代码
const io = require("socket.io")( {
  cors: {
    origin: "http://localhost:8080",
    methods: ["GET", "POST"]
  }
});

使用跨源资源共享,一个网站无法访问另一个网站的资源,直到通过添加headers

允许通过服务器
Access-Control-Allow-Origin: <Site Name> or Wild Card (*)

我认为您要么直接打开 HTML 文件,要么通过另一台服务器访问它,因此域会有所不同,例如。 HTML 文件在端口 http://localhost:8888 打开,WebSocket 服务器在端口 3000 运行 所以这就是你面临 CORS 的原因。

解决方案:

  1. CORS 可以在 socket.io 参考 this 或以下代码中处理:
const io = require("socket.io")(httpServer, {
  cors: {
    origin: "*",
    methods: ["GET", "POST"],
    credentials:true
  }
});
  1. 在网络服务器中使用 npm cors
  2. 添加HeaderAllow-Control-Allow-Origin
  3. 在同一端口上使用套接字服务器和 HTTP 服务器:
const httpServer = require("http").createServer();
const io = require("socket.io")(httpServer, {
  // ...
});

io.on("connection", (socket) => {
  // ...
});

httpServer.listen(3000);

更多参考资源:

  1. CORS:https://www.youtube.com/watch?v=4KHiSt0oLJ0
  2. Socket.IO: https://socket.io/docs/v3/server-initialization/
  3. https://www.youtube.com/watch?v=1BfCnjr_Vjg