带有 socket.io 的节点服务器不会建立连接

Posted

技术标签:

【中文标题】带有 socket.io 的节点服务器不会建立连接【英文标题】:Node server with socket.io wont establish connection 【发布时间】:2021-09-12 18:12:58 【问题描述】:

我最近刚刚开始了一个关于如何使用 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 策略阻止:否“访问控制允许-请求的资源上存在 Origin 标头。

然后我对什么是 CORS 进行了一些研究,据我了解,它就像一个限制不同 URL 之间连接的安全协议,出于安全原因,此错误需要标头?

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

"加载资源失败: 网络::ERR_CONNECTION_REFUSED"

我也不明白为什么在这个项目中我们从 index.html 中的 cdn 中提取 socket.io(我不确定它是如何工作的),然后使用 yarn 在服务器端,然后我们必须使用“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 的代码,但这次又收到了一条错误消息

CORS 已阻止从源“http://127.0.0.1:8080”访问“http://localhost:3000/socket.io/?EIO=3&transport=polling&t=NfUVBF5”处的 XMLHttpRequest策略:“Access-Control-Allow-Origin”标头的值“http://localhost:8080”不等于提供的来源。

我在 server.js 中编写了这段代码

const io = require("socket.io")( 
  cors: 
    origin: "http://localhost:8080",
    methods: ["GET", "POST"]
  
);

【问题讨论】:

如果没有适当的 cors 处理,您将无法通过 127.0.0.1:8080 访问该站点,并期望它连接到 localhost:3000 的端点,主机和端口与 cors 有关 【参考方案1】:

使用Cross Origin Resource Sharing,一个网站不能访问另一个网站的资源,直到它通过服务器允许通过添加标题

Access-Control-Allow-Origin: <Site Name> or Wild Card (*)

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

解决方案:

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

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

httpServer.listen(3000);

更多资源参考:

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

【讨论】:

感谢您提供此信息。这是非常有用的。我正在尝试实施您的解决方案。我在服务器文件夹中使用了命令“npm install cos”,并尝试在 server.js 中添加适当的标头以允许客户端站点的来源。您能否提供有关如何在代码中实现您的解决方案的说明? 我也收到错误:从源 '127.0.0.1:8080' 访问 XMLHttpRequest 已被 CORS 策略阻止:'Access-Control-Allow-Credentials' 的值响应中的标头为“”,当请求的凭据模式为“包含”时,它必须为“真”。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。 再添加一个标志,credentials:true + 也已编辑答案! 从源“127.0.0.1:8080”访问“localhost:3000/socket.io/…”处的 XMLHttpRequest 已被 CORS 策略阻止:“Access-Control-Allow-Origin”标头的值为“127.0.0.1:8080”不等于提供的原点。

以上是关于带有 socket.io 的节点服务器不会建立连接的主要内容,如果未能解决你的问题,请参考以下文章

使用带有webpack的socket.io连接到GDAX websocket api

带有 NGINX 和 http 2 的 Socket.io

如何在 android 上检查 socket.io 连接或断开连接?

带有 socket.io 和 expressjs 的节点集群

socket.io 中的连接限制

如何在 Socket.io 中与 Heroku 服务器建立 Socket 连接?