版本 4.6.0
2023 年 2 月 7 日
伺服器
錯誤修正
功能
基於承諾的確認
此提交在確認周圍新增了一些語法糖
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 Streams 為基礎,它將支援此功能。
新增於 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 選項和「標頭」事件可以達成解決方法,但這感覺更簡潔,而且也能用於升級要求。
新增於 24786e7。
中斷連線和斷線事件中的錯誤詳細資料
disconnect
事件現在將包含有關斷線原因的更多詳細資訊。
io.on("connection", (socket) => {
socket.on("disconnect", (reason, description) => {
console.log(description);
});
});
新增於 8aa9499。
自動移除空的子命名空間
此提交新增一個新的選項「cleanupEmptyChildNamespaces」。當啟用此選項(預設為停用)時,如果一個 socket 從動態命名空間斷線,且沒有其他 socket 連線到該命名空間,則會清除該命名空間,並關閉其適配器。
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() 傳回一個 active socket (b7dd891)
- 類型化:正確輸入帶有逾時功能的 emits (#1570) (33e4172)
功能
新的「addTrailingSlash」選項
預設新增的尾斜線現在可以停用
import { io } from "socket.io-client";
const socket = io("https://example.com", {
addTrailingSlash: false
});
在上述範例中,要求的網址將會是 https://example.com/socket.io
,而不是 https://example.com/socket.io/
。
新增於 21a6e12。
基於承諾的確認
此提交在確認周圍新增了一些語法糖
// 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
}
注意:不支援承諾的環境需要新增 polyfill才能使用此功能。
新增於 47b979d。
連線狀態復原
此功能允許用戶在暫時斷線後重新連線,並復原其 ID,以及接收斷線期間遺漏的封包。必須在伺服器端啟用。
在 socket
物件上新增一個名為 recovered
的布林屬性
socket.on("connect", () => {
console.log(socket.recovered); // whether the recovery was successful
});
新增於 54d5ee0(伺服器)和 b4e20c5(用戶端)。
重試機制
提供兩個新的選項
retries
:最大重試次數。超過限制,封包將會被捨棄。ackTimeout
:等待確認時使用的預設逾時時間(毫秒)(不要與現有的timeout
選項混淆,後者由管理員在連線期間使用)
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。