版本 4.6.0
2023 年 2 月 7 日
服务器
错误修复
功能
基于 Promise 的确认
此提交在确认周围添加了一些语法糖
emitWithAck()
try {
const responses = await io.timeout(1000).emitWithAck("some-event");
console.log(responses); // one response per client
} catch (e) {
// some clients did not acknowledge the event in the given delay
}
io.on("connection", async (socket) => {
// without timeout
const response = await socket.emitWithAck("hello", "world");
// with a specific timeout
try {
const response = await socket.timeout(1000).emitWithAck("hello", "world");
} catch (err) {
// the client did not acknowledge the event in the given delay
}
});
serverSideEmitWithAck()
try {
const responses = await io.timeout(1000).serverSideEmitWithAck("some-event");
console.log(responses); // one response per server (except itself)
} catch (e) {
// some servers did not acknowledge the event in the given delay
}
添加于 184f3cf.
连接状态恢复
此功能允许客户端在临时断开连接后重新连接并恢复其状态
- id
- 房间
- 数据
- 丢失的数据包
用法
import { Server } from "socket.io";
const io = new Server({
connectionStateRecovery: {
// default values
maxDisconnectionDuration: 2 * 60 * 1000,
skipMiddlewares: true,
},
});
io.on("connection", (socket) => {
console.log(socket.recovered); // whether the state was recovered or not
});
以下是它的工作原理
- 服务器在握手期间发送一个会话 ID(这与当前的
id
属性不同,该属性是公开的,可以自由共享) - 服务器还在每个数据包中包含一个偏移量(添加到数据数组的末尾,以实现向后兼容性)
- 在临时断开连接时,服务器会将客户端状态存储一段时间(在适配器级别实现)
- 在重新连接时,客户端会发送会话 ID 和它已处理的最后一个偏移量,服务器会尝试恢复状态
内存中适配器已经支持此功能,我们很快将更新 Postgres 和 MongoDB 适配器。我们还将创建一个基于 Redis 流 的新适配器,它将支持此功能。
添加于 54d5ee0.
与 Express 中间件的兼容性(真正的)
此功能在 Engine.IO 级别实现中间件,因为 Socket.IO 中间件用于命名空间授权,并且在经典的 HTTP 请求/响应周期中不会执行。
语法
io.engine.use((req, res, next) => {
// do something
next();
});
// with express-session
import session from "express-session";
io.engine.use(session({
secret: "keyboard cat",
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
// with helmet
import helmet from "helmet";
io.engine.use(helmet());
可以使用 allowRequest 选项和“headers”事件来实现一种变通方法,但这感觉更干净,并且也适用于升级请求。
添加于 24786e7.
断开连接和断开事件中的错误详细信息
disconnect
事件现在将包含有关断开连接原因的更多详细信息。
io.on("connection", (socket) => {
socket.on("disconnect", (reason, description) => {
console.log(description);
});
});
添加于 8aa9499.
自动删除空子命名空间
此提交添加了一个新选项“cleanupEmptyChildNamespaces”。启用此选项(默认情况下禁用),当套接字从动态命名空间断开连接时,如果没有任何其他套接字连接到它,则该命名空间将被清理,并且它的适配器将被关闭。
import { createServer } from "node:http";
import { Server } from "socket.io";
const httpServer = createServer();
const io = new Server(httpServer, {
cleanupEmptyChildNamespaces: true
});
添加于 5d9220b.
一个新的“addTrailingSlash”选项
现在可以禁用默认添加的尾部斜杠
import { createServer } from "node:http";
import { Server } from "socket.io";
const httpServer = createServer();
const io = new Server(httpServer, {
addTrailingSlash: false
});
在上面的示例中,客户端可以省略尾部斜杠,使用 /socket.io
而不是 /socket.io/
。
添加于 d0fd474.
性能改进
- 在广播时预先计算 WebSocket 帧 (da2b542)
依赖项
engine.io@~6.4.0
(https://github.com/socketio/engine.io/compare/6.2.1...6.4.0)ws@~8.11.0
(https://github.com/websockets/ws/compare/8.2.3...8.11.0)
客户端
错误修复
- 类型:不要公开特定于浏览器的类型 (4d6d95e)
- 确保 manager.socket() 返回一个活动的套接字 (b7dd891)
- 类型:正确地为带有超时的发射进行类型化 (#1570) (33e4172)
功能
一个新的“addTrailingSlash”选项
现在可以禁用默认添加的尾部斜杠
import { io } from "socket.io-client";
const socket = io("https://example.com", {
addTrailingSlash: false
});
在上面的示例中,请求 URL 将是 https://example.com/socket.io
而不是 https://example.com/socket.io/
。
添加于 21a6e12.
基于 Promise 的确认
此提交在确认周围添加了一些语法糖
// without timeout
const response = await socket.emitWithAck("hello", "world");
// with a specific timeout
try {
const response = await socket.timeout(1000).emitWithAck("hello", "world");
} catch (err) {
// the server did not acknowledge the event in the given delay
}
注意:不支持 Promise 的环境将需要添加一个 polyfill 才能使用此功能。
添加于 47b979d.
连接状态恢复
此功能允许客户端在临时断开连接后重新连接并恢复其 ID,并接收在断开连接间隙期间丢失的任何数据包。它必须在服务器端启用。
在 socket
对象上添加了一个名为 recovered
的新布尔属性
socket.on("connect", () => {
console.log(socket.recovered); // whether the recovery was successful
});
添加于 54d5ee0(服务器)和 b4e20c5(客户端)。
重试机制
有两个新选项可用
retries
:最大重试次数。超过限制,数据包将被丢弃。ackTimeout
:等待确认时使用的默认超时时间(以毫秒为单位)(不要与已存在的timeout
选项混淆,该选项由 Manager 在连接期间使用)
const socket = io({
retries: 3,
ackTimeout: 10000
});
// implicit ack
socket.emit("my-event");
// explicit ack
socket.emit("my-event", (err, val) => { /* ... */ });
// custom timeout (in that case the ackTimeout is optional)
socket.timeout(5000).emit("my-event", (err, val) => { /* ... */ });
在所有上面的示例中,“my-event”将被发送最多 4 次(1 + 3),直到服务器发送确认。
为每个数据包分配唯一 ID 是用户的责任,以便在服务器端允许重复数据消除。
添加于 655dce9.