我正在try 进行基本的WebSocket设置:
- 客户端:Next.js 14
- 服务器:Express
- WebSockets:socket-io
以下是最重要的文件:
服务器
我的Express服务器只有一个文件,看起来像这样:
index.ts
import * as socket from "socket.io";
import express from "express";
import http from "http";
import cors from "cors";
const app = express();
app.use(cors());
const server = http.create服务器(app);
const io = new socket.服务器(server, {
cors: {
origin: true,
},
});
io.on("connection", async (socket) => {
console.log(`Connection established`, socket.id);
socket.on("disconnect", () => {
console.log("user disconnected", socket.id);
});
socket.on("chat-message", (text) => {
console.log(text);
socket.broadcast.emit("chat-message", text);
});
});
server.listen(4000, () => {
console.log("服务器 running on http://localhost:4000");
});
客户端
在客户端上,我有两个相关文件:
app/lib/socket.ts
个
问题是:当应用程序第一次启动时,该代码会执行两次!我在服务器上(即在我运行Next.js应用程序的我的终端中)看到initialize socket
日志(log),在客户端(即在浏览器控制台中)看到and.
import { io } from 'socket.io-client';
const url = 'http://localhost:4000';
console.log(`initialize socket`);
export const socket = io(url);
app/page.tsx
个
"use client";
import { useState, useEffect } from "react";
import { socket } from "./lib/socket";
interface Message {
text: string;
}
export default function Home() {
const [message, setMessage] = useState("");
const [messageHistory, setMessageHistory] = useState<Message[]>([
{
text: "hello",
},
{
text: "world",
},
]);
const newMessageReceived = (e) => {
console.log(`received message: `, e);
setMessageHistory((oldMessageHistory) => [...oldMessageHistory, { text: e }]);
};
useEffect(() => {
socket.on("chat-message", newMessageReceived);
return () => {
console.log(`return from useEffect`);
socket.off("chat-message", newMessageReceived);
};
}, []);
const sendMessage = async (e: any) => {
e.preventDefault();
const newMessage = message;
setMessage("");
console.log(`sendMessage`, newMessage);
socket.emit("chat-message", newMessage);
setMessageHistory((oldMessageHistory) => [...oldMessageHistory, { text: newMessage }]);
};
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
<code className="font-mono font-bold">CoolChat 😎</code>
</p>
</div>
<div className="">
{messageHistory.map((message, i) => {
return <div key={i}>{message.text}</div>;
})}
</div>
<form
id="text-input-container"
className="bg-gray-300 py-4 px-2 w-full flex items-center justify-center"
onSubmit={sendMessage}
>
<div className="text-center bg-white w-full md:w-1/3 px-3 py-2 flex gap-3 rounded-xl drop-shadow-2xl">
<input
name="message"
value={message}
onChange={(e) => setMessage(e.target.value)}
id="message"
className="focus:outline-none px-2 flex-1 rounded-xl"
type="text"
placeholder="What do you want to say?"
/>
<button type="submit" className="rounded-xl px-3 py-2 bg-gray-600 text-gray-100 text-sm">
Send
</button>
</div>
</form>
</main>
);
}
下面是我运行代码时发生的情况:
- 以
npm run dev
启动服务器 - 服务器打印
服务器 running on http://localhost:4000
张 - 从
npm run dev
启动客户端 - 打开新的浏览器窗口并转到
localhost:3000
- 客户端(终端)打印:
initialize socket
- 客户端(浏览器)打印:
initialize socket
- 服务器打印
Connection established wQGEI_1USi_4T9n-AAAB
张 - 服务器打印
Connection established 1SPz0765uUEvMQgBAAAD
张 - (有时是第三次):服务器打印
Connection established BOAeHMUMeJ5zb2EJAAAF
- 打开第二个浏览器窗口并转到
localhost:3000
- 客户端(浏览器)打印:
initialize socket
- 服务器打印
Connection established um8qdP-yV9btkqVAAAAH
张 - 打开第三个浏览器窗口并转到
localhost:3000
- 客户端(浏览器)打印:
initialize socket
- 服务器打印
Connection established um8qdP-yV9btkqVAAAAH
张
因此,正如您所看到的,当我第一次连接到localhost:3000
时,套接字被初始化了两次-一次是服务器,一次是客户端.
在接下来的所有时间里,随着新浏览器窗口导航到localhost:3000
,套接字只初始化一次(在浏览器中,而不是在服务器上),正如我所预期的那样.
- 谁能解释一下为什么代码要执行两次,一次是在客户端(我希望它发生的地方),另一次是在服务器(我不希望它发生的地方)?这可能是显而易见的,但我是Next.js新手,所以如果有任何解释(也许还有一些其他资源的链接),我将不胜感激.
- 有人能解释一下如何防止这种情况,只在客户机上运行代码以防止"双重连接"吗?