要将用户名添加到消息中最简单,请将用户名添加到从客户端到服务器的消息中:
客户:
socket.emit("chat message", {username, message});
socket.on("chat message", ({username, message}) => {
console.log(username, message);
});
服务器:
io.on("connection", socket => {
socket.on("chat message", data => {
// send to all clients but the sender
socket.broadcast.emit("chat message", data);
});
});
如果您想“注册”一次用户名,您可以io.on("connection" ...
在服务器代码中的每个闭包中保留一个变量,然后使用一条"register username"
消息让客户端传达他们的用户名(或在服务器上为他们分配一个用户名,或者可选地协商一个有效的带有一系列消息的用户名):
server.js
:
const express = require("express"); // "^4.17.2"
const app = express();
const server = require("http").createServer(app);
const io = require("socket.io")(server); // "^4.4.1"
app.use(express.static("public"));
io.on("connection", socket => {
let username = "anonymous";
socket.on("chat message", message => {
io.emit("chat message", {username, message});
});
socket.on("register username", newUsername => {
username = newUsername;
});
});
server.listen(3000, () => console.log("server listening on port 3000"));
public/index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.js"></script>
</head>
<body>
<ul id="messages"></ul>
<form id="message-form">
<input autocomplete="off" />
<input type="submit" value="send">
</form>
<script>
const randomStr = (n=10) => [...Array(n)]
.map(e => String.fromCharCode(~~(Math.random() * 26) + 97))
.join("")
;
const username = prompt("what's your nickname?") || randomStr();
const socket = io.connect();
const messagesContainer = document.querySelector("#messages");
socket.on("connect", () => {
socket.emit("register username", username);
});
socket.on("chat message", ({username, message}) => {
const li = document.createElement("li");
li.textContent = `[${username}] ${message}`;
messagesContainer.appendChild(li);
});
document.querySelector("#message-form")
.addEventListener("submit", e => {
e.preventDefault();
if (e.target.elements[0].value) {
socket.emit("chat message", e.target.elements[0].value);
e.target.reset();
}
})
;
</script>
</body>
</html>
对于需要从每个套接字闭包访问所有活动用户的应用程序,您可以将用户名添加到共享范围内的对象中。
这是使用具有映射的对象的最小概念证明socket.id => username
:
public/index.html
:
(与上述基本相同,但有以下补充)
<!-- ... -->
<h3>current users:</h3>
<ul id="users"></ul>
<!-- ... -->
<script>
// ...
const usersEl = document.querySelector("#users");
socket.on("users", ({users}) => {
usersEl.innerHTML = "";
for (const user of users) {
const li = document.createElement("li");
li.textContent = user;
usersEl.appendChild(li);
}
});
// ...
</script>
<!-- ... -->
server.js
:
// ...
const usersBySocketId = {};
io.on("connection", socket => {
socket.on("disconnect", () => {
delete usersBySocketId[socket.id];
io.emit("users", {users: Object.values(usersBySocketId)});
});
socket.on("chat message", message => {
io.emit("chat message", {username: usersBySocketId[socket.id], message});
});
socket.on("register username", username => {
usersBySocketId[socket.id] = username;
io.emit("users", {users: Object.values(usersBySocketId)});
});
});
// ...
在更复杂的应用程序中,您通常希望在对象上存储其他数据。有时反向映射usernamme => socket.id
也很有用。
我还没有验证用户名的唯一性或其他属性,但这是另一个增加一些复杂性的典型要求。