NodeJS 使用Socket.io和Next.js

qvk1mo1f  于 2023-05-22  发布在  Node.js
关注(0)|答案(2)|浏览(274)

背景

我正在尝试使用Next.js建立和连接套接字。我遵循的是使用API调用来测试套接字服务器是否已经在运行的标准指南,如果没有,则创建一个。
我在pages/api/socket/io上有一个API脚本,看起来像这样:

import { Server } from "socket.io";

export default function SocketHandler(req, res) {

    if (res.socket.server.io) {
        console.log("Already set up");
        res.end();
        return;
    }

    const io = new Server(res.socket.server);

    // Event handler for client connections
    io.on('connection', (socket) => {
        const clientId = socket.id;
        console.log('A client connected');
        console.log(`A client connected. ID: ${clientId}`);
        io.emit('client-new', clientId);

        // Event handler for receiving messages from the client
        socket.on('message', (data) => {
            console.log('Received message:', data);
        });

        // Event handler for client disconnections
        socket.on('disconnect', () => {
            console.log('A client disconnected.');
        });
    });

    res.socket.server.io = io;
    res.end();
}

我在pages/chat.js下有一个页面,它ping /api/socket/io以确保套接字服务器正在运行,然后尝试连接到它。

import React, { useEffect, useState } from "react";
import io from "socket.io-client";

let socket;

const Page = () => {
    const [message, setMessage] = useState("");
    const [username, setUsername] = useState("");

    useEffect(() => {
        socketInitializer();

        return () => {
            socket.disconnect();
        };
    }, []);

    async function socketInitializer() {

        // ping the server to setup a socket if not already running
        await fetch("/api/socket/io");

        // Setup the Socket 
        socket = io({ path: "/api/socket/ping" });

        // Standard socket management
        socket.on('connect', () => {
            console.log('Connected to the server');
        });

        socket.on('disconnect', () => {
            console.log('Disconnected from the server');
        });

        socket.on('connect_error', (error) => {
            console.log('Connection error:', error);
        });

        socket.on('reconnect', (attemptNumber) => {
            console.log('Reconnected to the server. Attempt:', attemptNumber);
        });

        socket.on('reconnect_error', (error) => {
            console.log('Reconnection error:', error);
        });

        socket.on('reconnect_failed', () => {
            console.log('Failed to reconnect to the server');
        });

        // Manage socket message events
        socket.on('client-new', (message) => {
            console.log("new client", message);
        });

        socket.on('message', (message) => {
            console.log("Message", message);
        });

        socket.on('client-count', (count) => {
            console.log("clientCount", count)
        });

    }

    function handleSubmit(e) {
        e.preventDefault();

        socket.emit("message", {
            username,
            message
        });

        setMessage("");
    }

    return (
        <div>
            <h1>Chat app</h1>
            <h1>Enter a username</h1>

            <input value={username} onChange={(e) => setUsername(e.target.value)} />

            <div>
                <form onSubmit={handleSubmit}>
                    <input
                        name="message"
                        placeholder="enter your message"
                        value={message}
                        onChange={(e) => setMessage(e.target.value)}
                        autoComplete={"off"}
                    />
                </form>
            </div>
        </div>
    );
};

export default Page;

/api/socket/ping是一个简单的脚本,除了返回ok状态之外,它没有做太多的事情。我假设它应该检查服务器是否正在运行,并保存任何逻辑以检查客户端在将来是否仍然有效,但它不应该阻止客户端在此时连接。
它看起来像这样:

export default async function handler(req, res) {
    return res.status(200).send("OK");
}

问题

我遇到的问题是,似乎套接字服务器正在设置。但是,我无法让客户端连接。
我收到一个错误,提示我可能需要提供一些额外的配置选项作为客户端设置socket = io({ path: "/api/socket/ping" });的一部分,但我不确定从哪里开始。
我在本地主机端口3000上运行服务器。这是我得到的错误:

Connection error: Error: server error
    at Socket.onPacket (socket.js:318:1)
    at Emitter.emit (index.mjs:136:1)
    at Polling.onPacket (transport.js:97:1)
    at callback (polling.js:115:1)
    at Array.forEach (<anonymous>)
    at Polling.onData (polling.js:118:22)
    at Emitter.emit (index.mjs:136:1)
    at Request.onLoad (polling.js:361:1)
    at xhr.onreadystatechange (polling.js:297:1)

申请

请解释客户端无法连接的原因,并提出解决问题的建议。

lx0bsm1f

lx0bsm1f1#

import { Server } from "socket.io";
import cors from "cors";
import nextConnect from "next-connect";

const handler = nextConnect();

// Enable CORS
handler.use(cors());

handler.all((req, res) => {
  if (res.socket.server.io) {
    console.log("Already set up");
    res.end();
    return;
  }

  const io = new Server(res.socket.server);

  // Event handler for client connections
  io.on("connection", (socket) => {
    const clientId = socket.id;
    console.log("A client connected");
    console.log(`A client connected. ID: ${clientId}`);
    io.emit("client-new", clientId);

    // Event handler for receiving messages from the client
    socket.on("message", (data) => {
      console.log("Received message:", data);
    });

    // Event handler for client disconnections
    socket.on("disconnect", () => {
      console.log("A client disconnected.");
    });
  });

  res.socket.server.io = io;
  res.end();
});

export default handler;
8cdiaqws

8cdiaqws2#

@Louis的回答是正确的,将CORS确定为问题。我的解决方案有一点不同,我认为值得分享我的方法。
我在我的项目yarn add cors中添加了cors。然后修改我的io.js API端点,看起来像这样:

io.js

import { Server } from "socket.io";
import cors from 'cors';

// Create a new instance of the CORS middleware
const corsMiddleware = cors();

export default function SocketHandler(req, res) {
    if (res.socket.server.io) {
        console.log("Already set up");
        res.end();
        return;
    }

    const io = new Server(res.socket.server, {
        path: "/api/socket/ping",
        addTrailingSlash: false
    });

    // Event handler for client connections
    io.on('connection', (socket) => {
        const clientId = socket.id;
        console.log('A client connected');
        console.log(`A client connected. ID: ${clientId}`);
        io.emit('client-new', clientId);

        // Event handler for receiving messages from the client
        socket.on('message', (data) => {
            console.log('Received message:', data);
        });

        // Event handler for client disconnections
        socket.on('disconnect', () => {
            console.log('A client disconnected.');
        });
    });

    // Apply the CORS middleware to the request and response
    corsMiddleware(req, res, () => {
        res.socket.server.io = io;
        res.end();
    });
}

相关问题