バージョン 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
- rooms
- data
- 未処理のパケット
使い方
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オプションと「headers」イベントを使用することで回避策は可能でしたが、これはよりクリーンで、アップグレードリクエストでも機能します。
24786e7で追加されました。
disconnectingおよびdisconnectイベントのエラー詳細
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)
- 型定義: タイムアウト付きのemitを適切に型定義 (#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
}
注: Promisesをサポートしない環境では、この機能を使用するためにポリフィルを追加する必要があります。
47b979dで追加されました。
接続状態の復元
この機能により、クライアントは一時的な切断後に再接続し、IDを復元し、切断中に失われたパケットを受信できます。サーバー側で有効にする必要があります。
socket
オブジェクトに、recovered
という名前の新しいブール値属性が追加されます。
socket.on("connect", () => {
console.log(socket.recovered); // whether the recovery was successful
});
54d5ee0(サーバー)およびb4e20c5(クライアント)で追加されました。
再試行メカニズム
2つの新しいオプションが利用可能です。
retries
: 最大再試行回数。制限を超えると、パケットは破棄されます。ackTimeout
: 確認応答を待機する際に使用されるデフォルトのタイムアウト(ミリ秒単位)(接続中にManagerによって使用される既存の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で追加されました。